diff options
| author | Steve Piercy <web@stevepiercy.com> | 2015-10-22 09:32:42 -0700 |
|---|---|---|
| committer | Steve Piercy <web@stevepiercy.com> | 2015-10-22 09:32:42 -0700 |
| commit | 4ade6de3bef51483a442fc404c350b3ce9c10988 (patch) | |
| tree | 6c984ce9c6164d0615640da37d844444175b53b2 /docs | |
| parent | d4221720b8409eafb65b301562be327af0196c7e (diff) | |
| download | pyramid-4ade6de3bef51483a442fc404c350b3ce9c10988.tar.gz pyramid-4ade6de3bef51483a442fc404c350b3ce9c10988.tar.bz2 pyramid-4ade6de3bef51483a442fc404c350b3ce9c10988.zip | |
minor grammar, rewrap 79 columns, some .rst syntax fixes
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/narr/testing.rst | 195 |
1 files changed, 95 insertions, 100 deletions
diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index ecda57489..c05ee41ad 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -13,34 +13,32 @@ application. In this context, a "unit" is often a function or a method of a class instance. The unit is also referred to as a "unit under test". The goal of a single unit test is to test **only** some permutation of the -"unit under test". If you write a unit test that aims to verify the result -of a particular codepath through a Python function, you need only be -concerned about testing the code that *lives in the function body itself*. -If the function accepts a parameter that represents a complex application -"domain object" (such as a resource, a database connection, or an SMTP -server), the argument provided to this function during a unit test *need not -be* and likely *should not be* a "real" implementation object. For example, -although a particular function implementation may accept an argument that -represents an SMTP server object, and the function may call a method of this -object when the system is operating normally that would result in an email -being sent, a unit test of this codepath of the function does *not* need to -test that an email is actually sent. It just needs to make sure that the -function calls the method of the object provided as an argument that *would* -send an email if the argument happened to be the "real" implementation of an -SMTP server object. +"unit under test". If you write a unit test that aims to verify the result of +a particular codepath through a Python function, you need only be concerned +about testing the code that *lives in the function body itself*. If the +function accepts a parameter that represents a complex application "domain +object" (such as a resource, a database connection, or an SMTP server), the +argument provided to this function during a unit test *need not be* and likely +*should not be* a "real" implementation object. For example, although a +particular function implementation may accept an argument that represents an +SMTP server object, and the function may call a method of this object when the +system is operating normally that would result in an email being sent, a unit +test of this codepath of the function does *not* need to test that an email is +actually sent. It just needs to make sure that the function calls the method +of the object provided as an argument that *would* send an email if the +argument happened to be the "real" implementation of an SMTP server object. An *integration test*, on the other hand, is a different form of testing in which the interaction between two or more "units" is explicitly tested. -Integration tests verify that the components of your application work -together. You *might* make sure that an email was actually sent in an -integration test. +Integration tests verify that the components of your application work together. +You *might* make sure that an email was actually sent in an integration test. A *functional test* is a form of integration test in which the application is -run "literally". You would *have to* make sure that an email was actually -sent in a functional test, because it tests your code end to end. +run "literally". You would *have to* make sure that an email was actually sent +in a functional test, because it tests your code end to end. -It is often considered best practice to write each type of tests for any -given codebase. Unit testing often provides the opportunity to obtain better +It is often considered best practice to write each type of tests for any given +codebase. Unit testing often provides the opportunity to obtain better "coverage": it's usually possible to supply a unit under test with arguments and/or an environment which causes *all* of its potential codepaths to be executed. This is usually not as easy to do with a set of integration or @@ -55,9 +53,9 @@ integration tests. A good :mod:`unittest` tutorial is available within `Dive Into Python <http://www.diveintopython.net/unit_testing/index.html>`_ by Mark Pilgrim. -:app:`Pyramid` provides a number of facilities that make unit, integration, -and functional tests easier to write. The facilities become particularly -useful when your code calls into :app:`Pyramid` -related framework functions. +:app:`Pyramid` provides a number of facilities that make unit, integration, and +functional tests easier to write. The facilities become particularly useful +when your code calls into :app:`Pyramid`-related framework functions. .. index:: single: test setup @@ -67,42 +65,41 @@ useful when your code calls into :app:`Pyramid` -related framework functions. .. _test_setup_and_teardown: Test Set Up and Tear Down --------------------------- +------------------------- :app:`Pyramid` uses a "global" (actually :term:`thread local`) data structure to hold two items: the current :term:`request` and the current :term:`application registry`. These data structures are available via the :func:`pyramid.threadlocal.get_current_request` and -:func:`pyramid.threadlocal.get_current_registry` functions, respectively. -See :ref:`threadlocals_chapter` for information about these functions and the -data structures they return. +:func:`pyramid.threadlocal.get_current_registry` functions, respectively. See +:ref:`threadlocals_chapter` for information about these functions and the data +structures they return. If your code uses these ``get_current_*`` functions or calls :app:`Pyramid` code which uses ``get_current_*`` functions, you will need to call :func:`pyramid.testing.setUp` in your test setup and you will need to call :func:`pyramid.testing.tearDown` in your test teardown. -:func:`~pyramid.testing.setUp` pushes a registry onto the :term:`thread -local` stack, which makes the ``get_current_*`` functions work. It returns a +:func:`~pyramid.testing.setUp` pushes a registry onto the :term:`thread local` +stack, which makes the ``get_current_*`` functions work. It returns a :term:`Configurator` object which can be used to perform extra configuration required by the code under test. :func:`~pyramid.testing.tearDown` pops the thread local stack. -Normally when a Configurator is used directly with the ``main`` block of -a Pyramid application, it defers performing any "real work" until its -``.commit`` method is called (often implicitly by the -:meth:`pyramid.config.Configurator.make_wsgi_app` method). The -Configurator returned by :func:`~pyramid.testing.setUp` is an -*autocommitting* Configurator, however, which performs all actions -implied by methods called on it immediately. This is more convenient -for unit-testing purposes than needing to call -:meth:`pyramid.config.Configurator.commit` in each test after adding -extra configuration statements. +Normally when a Configurator is used directly with the ``main`` block of a +Pyramid application, it defers performing any "real work" until its ``.commit`` +method is called (often implicitly by the +:meth:`pyramid.config.Configurator.make_wsgi_app` method). The Configurator +returned by :func:`~pyramid.testing.setUp` is an *autocommitting* Configurator, +however, which performs all actions implied by methods called on it +immediately. This is more convenient for unit testing purposes than needing to +call :meth:`pyramid.config.Configurator.commit` in each test after adding extra +configuration statements. The use of the :func:`~pyramid.testing.setUp` and -:func:`~pyramid.testing.tearDown` functions allows you to supply each unit -test method in a test case with an environment that has an isolated registry -and an isolated request for the duration of a single test. Here's an example -of using this feature: +:func:`~pyramid.testing.tearDown` functions allows you to supply each unit test +method in a test case with an environment that has an isolated registry and an +isolated request for the duration of a single test. Here's an example of using +this feature: .. code-block:: python :linenos: @@ -117,22 +114,21 @@ of using this feature: def tearDown(self): testing.tearDown() -The above will make sure that -:func:`~pyramid.threadlocal.get_current_registry` called within a test -case method of ``MyTest`` will return the :term:`application registry` -associated with the ``config`` Configurator instance. Each test case -method attached to ``MyTest`` will use an isolated registry. +The above will make sure that :func:`~pyramid.threadlocal.get_current_registry` +called within a test case method of ``MyTest`` will return the +:term:`application registry` associated with the ``config`` Configurator +instance. Each test case method attached to ``MyTest`` will use an isolated +registry. The :func:`~pyramid.testing.setUp` and :func:`~pyramid.testing.tearDown` -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. +functions accept 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 -:term:`request` object into the :func:`pyramid.testing.setUp` within the -``setUp`` method of your test: +can pass a :term:`request` object into the :func:`pyramid.testing.setUp` within +the ``setUp`` method of your test: .. code-block:: python :linenos: @@ -148,24 +144,23 @@ can pass a def tearDown(self): testing.tearDown() -If you pass a :term:`request` object into :func:`pyramid.testing.setUp` -within your test case's ``setUp``, any test method attached to the -``MyTest`` test case that directly or indirectly calls +If you pass a :term:`request` object into :func:`pyramid.testing.setUp` within +your test case's ``setUp``, any test method attached to the ``MyTest`` test +case that directly or indirectly calls :func:`~pyramid.threadlocal.get_current_request` will receive the request object. Otherwise, during testing, -:func:`~pyramid.threadlocal.get_current_request` will return ``None``. -We use a "dummy" request implementation supplied by -:class:`pyramid.testing.DummyRequest` because it's easier to construct -than a "real" :app:`Pyramid` request object. +:func:`~pyramid.threadlocal.get_current_request` will return ``None``. We use a +"dummy" request implementation supplied by +:class:`pyramid.testing.DummyRequest` because it's easier to construct than a +"real" :app:`Pyramid` request object. Test setup using a context manager ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -An alternative style of setting up a test configuration is to use the -`with` statement and :func:`pyramid.testing.testConfig` to create a -context manager. The context manager will call -:func:`pyramid.testing.setUp` before the code under test and -:func:`pyramid.testing.tearDown` afterwards. +An alternative style of setting up a test configuration is to use the ``with`` +statement and :func:`pyramid.testing.testConfig` to create a context manager. +The context manager will call :func:`pyramid.testing.setUp` before the code +under test and :func:`pyramid.testing.tearDown` afterwards. This style is useful for small self-contained tests. For example: @@ -193,8 +188,8 @@ they're used by frameworks. Sorry. So here's a rule of thumb: if you don't about any of this, but you still want to write test code, just always call :func:`pyramid.testing.setUp` in your test's ``setUp`` method and :func:`pyramid.testing.tearDown` in your tests' ``tearDown`` method. This -won't really hurt anything if the application you're testing does not call -any ``get_current*`` function. +won't really hurt anything if the application you're testing does not call any +``get_current*`` function. .. index:: single: pyramid.testing @@ -225,15 +220,15 @@ function. .. note:: This code implies that you have defined a renderer imperatively in a - relevant :class:`pyramid.config.Configurator` instance, - otherwise it would fail when run normally. + relevant :class:`pyramid.config.Configurator` instance, otherwise it would + fail when run normally. Without doing anything special during a unit test, the call to :meth:`~pyramid.request.Request.has_permission` in this view function will always return a ``True`` value. When a :app:`Pyramid` application starts -normally, it will populate a :term:`application registry` using +normally, it will populate an :term:`application registry` using :term:`configuration declaration` calls made against a :term:`Configurator`. -But if this application registry is not created and populated (e.g. by +But if this application registry is not created and populated (e.g., by initializing the configurator with an authorization policy), like when you invoke application code via a unit test, :app:`Pyramid` API functions will tend to either fail or return default results. So how do you test the branch of the @@ -283,10 +278,10 @@ In the above example, we create a ``MyTest`` test case that inherits from be found when ``setup.py test`` is run. It has two test methods. The first test method, ``test_view_fn_forbidden`` tests the ``view_fn`` when -the authentication policy forbids the current user the ``edit`` permission. -Its third line registers a "dummy" "non-permissive" authorization policy -using the :meth:`~pyramid.config.Configurator.testing_securitypolicy` method, -which is a special helper method for unit testing. +the authentication policy forbids the current user the ``edit`` permission. Its +third line registers a "dummy" "non-permissive" authorization policy using the +:meth:`~pyramid.config.Configurator.testing_securitypolicy` method, which is a +special helper method for unit testing. We then create a :class:`pyramid.testing.DummyRequest` object which simulates a WebOb request object API. A :class:`pyramid.testing.DummyRequest` is a request @@ -300,25 +295,25 @@ access. We check that the view function raises a The second test method, named ``test_view_fn_allowed``, tests the alternate case, where the authentication policy allows access. Notice that we pass -different values to -:meth:`~pyramid.config.Configurator.testing_securitypolicy` to obtain this -result. We assert at the end of this that the view function returns a value. +different values to :meth:`~pyramid.config.Configurator.testing_securitypolicy` +to obtain this result. We assert at the end of this that the view function +returns a value. Note that the test calls the :func:`pyramid.testing.setUp` function in its ``setUp`` method and the :func:`pyramid.testing.tearDown` function in its -``tearDown`` method. We assign the result of :func:`pyramid.testing.setUp` -as ``config`` on the unittest class. This is a :term:`Configurator` object -and all methods of the configurator can be called as necessary within -tests. If you use any of the :class:`~pyramid.config.Configurator` APIs during -testing, be sure to use this pattern in your test case's ``setUp`` and -``tearDown``; these methods make sure you're using a "fresh" -:term:`application registry` per test run. - -See the :ref:`testing_module` chapter for the entire :app:`Pyramid` -specific +``tearDown`` method. We assign the result of :func:`pyramid.testing.setUp` as +``config`` on the unittest class. This is a :term:`Configurator` object and +all methods of the configurator can be called as necessary within tests. If you +use any of the :class:`~pyramid.config.Configurator` APIs during testing, be +sure to use this pattern in your test case's ``setUp`` and ``tearDown``; these +methods make sure you're using a "fresh" :term:`application registry` per test +run. + +See the :ref:`testing_module` chapter for the entire :app:`Pyramid`-specific testing API. This chapter describes APIs for registering a security policy, -registering resources at paths, registering event listeners, registering -views and view permissions, and classes representing "dummy" implementations -of a request and a resource. +registering resources at paths, registering event listeners, registering views +and view permissions, and classes representing "dummy" implementations of a +request and a resource. .. seealso:: @@ -392,7 +387,7 @@ In Pyramid, functional tests are typically written using the :term:`WebTest` package, which provides APIs for invoking HTTP(S) requests to your application. Regardless of which testing :term:`package` you use, ensure to add a -``tests_require`` dependency on that package to to your application's +``tests_require`` dependency on that package to your application's ``setup.py`` file: .. literalinclude:: MyProject/setup.py @@ -400,7 +395,7 @@ Regardless of which testing :term:`package` you use, ensure to add a :emphasize-lines: 26-28,48 :language: python -Assuming your :term:`package` is named ``myproject``, which contains a +Let us assume 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: @@ -408,8 +403,8 @@ that returns a HTML body when the root URL is invoked: :linenos: :language: python -Then the following example functional test (shown below) demonstrates invoking -the :term:`view` shown above: +Then the following example functional test demonstrates invoking the above +:term:`view`: .. literalinclude:: MyProject/myproject/tests.py :linenos: @@ -419,9 +414,9 @@ the :term:`view` shown above: 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`` +``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. +See the :term:`WebTest` documentation for further information about the methods +available to a :class:`webtest.app.TestApp` instance. |
