Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,23 @@ a special ``json`` attribute appended to the ``Response`` object::
response = self.client.get("/ajax/")
self.assertEquals(response.json, dict(success=True))


Single app instance
-------------------

In some cases, creating the app instance can be expensive. If you want to create one
app instance per TestCase class, you can use the ``create_app_once`` flag. This works
on both TestCase and LiveServerTestCase and is not enabled by default::

from flask_testing import TestCase

class MyTest(TestCase):
create_app_once = True

def test_something(self):
pass


Opt to not render the templates
-------------------------------

Expand Down
31 changes: 26 additions & 5 deletions flask_testing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
except ImportError: # pragma: no cover
_is_signals = False

__all__ = ["TestCase"]
__all__ = ('TestCase', 'LiveServerTestCase')


class ContextVariableDoesNotExist(Exception):
Expand Down Expand Up @@ -110,7 +110,28 @@ def _check_for_signals_support():
)


class TestCase(unittest.TestCase):
class SingletonAppMixin(object):
create_app_once = False
_app_instance = None

def _get_or_create_app(self):
"""
This is a lazy way of doing class setup since we want to be consistent
and not have users call super in setUpClass if they do not call it in
setUp. Returns the singleton app if the test case has specified using
a single app.
"""
cls = self.__class__
if not cls.create_app_once:
return self.create_app()

if not cls._app_instance:
cls._app_instance = self.create_app()

return cls._app_instance


class TestCase(unittest.TestCase, SingletonAppMixin):
render_templates = True
run_gc_after_test = False

Expand Down Expand Up @@ -141,7 +162,7 @@ def debug(self):
self._post_teardown()

def _pre_setup(self):
self.app = self.create_app()
self.app = self._get_or_create_app()

self._orig_response_class = self.app.response_class
self.app.response_class = _make_test_response(self.app.response_class)
Expand Down Expand Up @@ -410,8 +431,8 @@ def assert500(self, response, message=None):

# A LiveServerTestCase useful with Selenium or headless browsers
# Inspired by https://docs.djangoproject.com/en/dev/topics/testing/#django.test.LiveServerTestCase
class LiveServerTestCase(unittest.TestCase, SingletonAppMixin):

class LiveServerTestCase(unittest.TestCase):
def create_app(self):
"""
Create your Flask app here, with any
Expand All @@ -426,7 +447,7 @@ def __call__(self, result=None):
"""

# Get the app
self.app = self.create_app()
self.app = self._get_or_create_app()

self._configured_port = self.app.config.get('LIVESERVER_PORT', 5000)
self._port_value = multiprocessing.Value('i', self._configured_port)
Expand Down
8 changes: 5 additions & 3 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@

from .test_twill import TestTwill, TestTwillDeprecated
from .test_utils import TestSetup, TestSetupFailure, TestClientUtils, \
TestLiveServer, TestTeardownGraceful, TestRenderTemplates, \
TestNotRenderTemplates, TestRestoreTheRealRender, \
TestLiveServerOSPicksPort
TestLiveServer, TestTeardownGraceful, TestRenderTemplates, \
TestNotRenderTemplates, TestRestoreTheRealRender, TestSingletonApp, \
TestLiveServerOSPicksPort, TestLiveServerSingletonApp


def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestSetup))
suite.addTest(unittest.makeSuite(TestSetupFailure))
suite.addTest(unittest.makeSuite(TestSingletonApp))
suite.addTest(unittest.makeSuite(TestClientUtils))
suite.addTest(unittest.makeSuite(TestLiveServer))
suite.addTest(unittest.makeSuite(TestLiveServerOSPicksPort))
suite.addTest(unittest.makeSuite(TestLiveServerSingletonApp))
suite.addTest(unittest.makeSuite(TestTeardownGraceful))
suite.addTest(unittest.makeSuite(TestRenderTemplates))
suite.addTest(unittest.makeSuite(TestNotRenderTemplates))
Expand Down
32 changes: 32 additions & 0 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ def test_remove_testcase_attributes(self):

del self.app


class TestSingletonApp(TestCase):
create_app_once = True
apps_created = 0

def create_app(self):
self.__class__.apps_created += 1
return create_app()

def test_create_app_once(self):
self.assertEqual(self.apps_created, 1)

def test_create_app_once_sanity(self):
# In case sorting method changes
self.assertEqual(self.apps_created, 1)

class TestClientUtils(TestCase):

def create_app(self):
Expand Down Expand Up @@ -245,6 +261,22 @@ def create_app(self):
return app


class TestLiveServerSingletonApp(BaseTestLiveServer):
create_app_once = True
apps_created = 0

def create_app(self):
self.__class__.apps_created += 1
return create_app()

def test_created_single_app(self):
self.assertEqual(1, self.apps_created)

def test_created_single_app_sanity(self):
# In case they run out of order
self.assertEqual(1, self.apps_created)


class TestNotRenderTemplates(TestCase):

render_templates = False
Expand Down