diff options
| author | Matt Russell <matthew.russell@horizon5.org> | 2014-11-19 23:06:17 +0000 |
|---|---|---|
| committer | Matt Russell <matthew.russell@horizon5.org> | 2014-11-25 19:50:22 +0000 |
| commit | 138706a24bd8e7051c60942c2789d8c16b4ca2ed (patch) | |
| tree | 8891fc1d464743569340ad3c60ceeda04410e16a /docs | |
| parent | 2b59a35c4b5ec0f7052aacce3ffa66ce74cbae56 (diff) | |
| download | pyramid-138706a24bd8e7051c60942c2789d8c16b4ca2ed.tar.gz pyramid-138706a24bd8e7051c60942c2789d8c16b4ca2ed.tar.bz2 pyramid-138706a24bd8e7051c60942c2789d8c16b4ca2ed.zip | |
Include code examples for integration and functional tests in docs #1001
Wrap lines as per convention.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/narr/MyProject/myproject/tests.py | 37 | ||||
| -rw-r--r-- | docs/narr/MyProject/setup.py | 45 | ||||
| -rw-r--r-- | docs/narr/testing.rst | 142 |
3 files changed, 131 insertions, 93 deletions
diff --git a/docs/narr/MyProject/myproject/tests.py b/docs/narr/MyProject/myproject/tests.py index 64dcab1d5..8c60407e5 100644 --- a/docs/narr/MyProject/myproject/tests.py +++ b/docs/narr/MyProject/myproject/tests.py @@ -15,3 +15,40 @@ class ViewTests(unittest.TestCase): request = testing.DummyRequest() info = my_view(request) self.assertEqual(info['project'], 'MyProject') + +class ViewIntegrationTests(unittest.TestCase): + def setUp(self): + """ This sets up the application registry with the + registrations your application declares in its ``includeme`` + function. + """ + self.config = testing.setUp() + self.config.include('myproject') + + def tearDown(self): + """ Clear out the application registry """ + testing.tearDown() + + def test_my_view(self): + from myproject.views import my_view + request = testing.DummyRequest() + result = my_view(request) + self.assertEqual(result.status, '200 OK') + body = result.app_iter[0] + self.assertTrue('Welcome to' in body) + self.assertEqual(len(result.headerlist), 2) + self.assertEqual(result.headerlist[0], + ('Content-Type', 'text/html; charset=UTF-8')) + self.assertEqual(result.headerlist[1], ('Content-Length', + str(len(body)))) + +class FunctionalTests(unittest.TestCase): + def setUp(self): + from myproject import main + app = main({}) + from webtest import TestApp + self.testapp = TestApp(app) + + def test_root(self): + res = self.testapp.get('/', status=200) + self.assertTrue('Pyramid' in res.body) diff --git a/docs/narr/MyProject/setup.py b/docs/narr/MyProject/setup.py index 8c019af51..9f34540a7 100644 --- a/docs/narr/MyProject/setup.py +++ b/docs/narr/MyProject/setup.py @@ -1,30 +1,42 @@ -import os +"""Setup for the MyProject package. +""" +import os from setuptools import setup, find_packages -here = os.path.abspath(os.path.dirname(__file__)) -with open(os.path.join(here, 'README.txt')) as f: - README = f.read() -with open(os.path.join(here, 'CHANGES.txt')) as f: - CHANGES = f.read() -requires = [ +HERE = os.path.abspath(os.path.dirname(__file__)) + + +with open(os.path.join(HERE, 'README.txt')) as fp: + README = fp.read() + + +with open(os.path.join(HERE, 'CHANGES.txt')) as fp: + CHANGES = fp.read() + + +REQUIRES = [ 'pyramid', 'pyramid_chameleon', 'pyramid_debugtoolbar', 'waitress', ] +TESTS_REQUIRE = [ + 'webtest' + ] + setup(name='MyProject', version='0.0', description='MyProject', long_description=README + '\n\n' + CHANGES, classifiers=[ - "Programming Language :: Python", - "Framework :: Pyramid", - "Topic :: Internet :: WWW/HTTP", - "Topic :: Internet :: WWW/HTTP :: WSGI :: Application", - ], + 'Programming Language :: Python', + 'Framework :: Pyramid', + 'Topic :: Internet :: WWW/HTTP', + 'Topic :: Internet :: WWW/HTTP :: WSGI :: Application', + ], author='', author_email='', url='', @@ -32,11 +44,10 @@ setup(name='MyProject', packages=find_packages(), include_package_data=True, zip_safe=False, - install_requires=requires, - tests_require=requires, - test_suite="myproject", + install_requires=REQUIRES, + tests_require=TESTS_REQUIRE, + test_suite='myproject', entry_points="""\ [paste.app_factory] main = myproject:main - """, - ) + """) diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index e001ad81c..3620f5e11 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -128,8 +128,9 @@ functions accepts various arguments that influence the environment of the test. See the :ref:`testing_module` API for information about the extra arguments supported by these functions. -If you also want to make :func:`~pyramid.threadlocal.get_current_request` return something -other than ``None`` during the course of a single test, you can pass a +If you also want to make :func:`~pyramid.threadlocal.get_current_request` +return something other than ``None`` during the course of a single test, you +can pass a :term:`request` object into the :func:`pyramid.testing.setUp` within the ``setUp`` method of your test: @@ -333,66 +334,49 @@ Creating Integration Tests -------------------------- In :app:`Pyramid`, a *unit test* typically relies on "mock" or "dummy" -implementations to give the code under test only enough context to run. +implementations to give the code under test enough context to run. "Integration testing" implies another sort of testing. In the context of a -:app:`Pyramid` integration test, the test logic tests the functionality of -some code *and* its integration with the rest of the :app:`Pyramid` +:app:`Pyramid` integration test, the test logic exercises the functionality of +the code under test *and* its integration with the rest of the :app:`Pyramid` framework. -In :app:`Pyramid` applications that are plugins to Pyramid, you can create an -integration test by including its ``includeme`` function via -:meth:`pyramid.config.Configurator.include` in the test's setup code. This -causes the entire :app:`Pyramid` environment to be set up and torn down as if -your application was running "for real". This is a heavy-hammer way of -making sure that your tests have enough context to run properly, and it tests -your code's integration with the rest of :app:`Pyramid`. +Creating an integration test for a :app:`Pyramid` application usually means +invoking the application's ``includeme`` function via +:meth:`pyramid.config.Configurator.include` within the test's setup code. This +causes the entire :app:`Pyramid` environment to be set up, simulating what +happens when your application is run "for real". This is a heavy-hammer way of +making sure that your tests have enough context to run properly, and tests your +code's integration with the rest of :app:`Pyramid`. -Let's demonstrate this by showing an integration test for a view. The below -test assumes that your application's package name is ``myapp``, and that -there is a ``views`` module in the app with a function with the name -``my_view`` in it that returns the response 'Welcome to this application' -after accessing some values that require a fully set up environment. +.. seealso:: -.. code-block:: python - :linenos: + See more information about :app:`Pyramid`'s ``includme`` function. - import unittest +Let's demonstrate this by showing an integration test for a view. - from pyramid import testing +Given the following view definition, which assumes that your application's +:term:`package` name is ``myproject``, and within that :term:`package` there +exists a module ``views``, which in turn contains a :term:`view` function named +``my_view``: - class ViewIntegrationTests(unittest.TestCase): - def setUp(self): - """ This sets up the application registry with the - registrations your application declares in its ``includeme`` - function. - """ - import myapp - self.config = testing.setUp() - self.config.include('myapp') + .. literalinclude:: MyProject/myproject/views.py + :linenos: + :lines: 1-6 + :language: python - def tearDown(self): - """ Clear out the application registry """ - testing.tearDown() +You'd then create a ``tests`` module within your ``myproject`` package, +containing the following test code: - def test_my_view(self): - from myapp.views import my_view - request = testing.DummyRequest() - result = my_view(request) - self.assertEqual(result.status, '200 OK') - body = result.app_iter[0] - self.assertTrue('Welcome to' in body) - self.assertEqual(len(result.headerlist), 2) - self.assertEqual(result.headerlist[0], - ('Content-Type', 'text/html; charset=UTF-8')) - self.assertEqual(result.headerlist[1], ('Content-Length', - str(len(body)))) - -Unless you cannot avoid it, you should prefer writing unit tests that use the -:class:`~pyramid.config.Configurator` API to set up the right "mock" -registrations rather than creating an integration test. Unit tests will run -faster (because they do less for each test) and the result of a unit test is -usually easier to make assertions about. + .. literalinclude:: MyProject/myproject/tests.py + :linenos: + :pyobject: ViewIntegrationTests + :language: python + +Writing unit tests that use the :class:`~pyramid.config.Configurator` API to +set up the right "mock" registrations is often preferred to creating +integration tests. Unit tests will run faster (because they do less for each +test) and are usually easier to reason about. .. index:: single: functional tests @@ -404,34 +388,40 @@ Creating Functional Tests Functional tests test your literal application. -The below test assumes that your application's package name is ``myapp``, and -that there is a view that returns an HTML body when the root URL is invoked. -It further assumes that you've added a ``tests_require`` dependency on the -``WebTest`` package within your ``setup.py`` file. :term:`WebTest` is a -functional testing package written by Ian Bicking. +In Pyramid, functional tests are typically written using the :term:`WebTest` +package, which provides APIs for invoking HTTP(S) requests to your application. -.. code-block:: python - :linenos: +Regardless of which testing :term:`package` you use, ensure to add a +``tests_require`` dependency on that package to to your application's +``setup.py`` file: - import unittest + .. literalinclude:: MyProject/setup.py + :linenos: + :emphasize-lines: 26-28,48 + :language: python - class FunctionalTests(unittest.TestCase): - def setUp(self): - from myapp import main - app = main({}) - from webtest import TestApp - self.testapp = TestApp(app) - - def test_root(self): - res = self.testapp.get('/', status=200) - self.assertTrue('Pyramid' in res.body) - -When this test is run, each test creates a "real" WSGI application using the -``main`` function in your ``myapp.__init__`` module and uses :term:`WebTest` -to wrap that WSGI application. It assigns the result to ``self.testapp``. -In the test named ``test_root``, we use the testapp's ``get`` method to -invoke the root URL. We then assert that the returned HTML has the string -``Pyramid`` in it. +Assuming your :term:`package` is named ``myproject``, which contains a +``views`` module, which in turn contains a :term:`view` function ``my_view`` +that returns a HTML body when the root URL is invoked: + + .. literalinclude:: MyProject/myproject/views.py + :linenos: + :language: python + +Then the following example functional test (shown below) demonstrates invoking +the :term:`view` shown above: + + .. literalinclude:: MyProject/myproject/tests.py + :linenos: + :pyobject: FunctionalTests + :language: python + +When this test is run, each test method creates a "real" :term:`WSGI` +application using the ``main`` function in your ``myproject.__init__`` module, +using :term:`WebTest` to wrap that WSGI application. It assigns the result to +``self.testapp``. In the test named ``test_root``. The ``TestApp``'s ``get`` +method is used to invoke the root URL. Finally, an assertion is made that the +returned HTML contains the text ``MyProject``. See the :term:`WebTest` documentation for further information about the methods available to a :class:`webtest.app.TestApp` instance. |
