diff options
| author | Chris McDonough <chrism@plope.com> | 2011-01-19 19:43:45 -0500 |
|---|---|---|
| committer | Chris McDonough <chrism@plope.com> | 2011-01-19 19:43:45 -0500 |
| commit | 9904b3546478e3299e41d8552370e722dfbd08d4 (patch) | |
| tree | 6e1410aa454d617a4dc8a6a0d176204e83a05d88 | |
| parent | 9d6a1345f30154410f19359008a79b07b3901a7a (diff) | |
| download | pyramid-9904b3546478e3299e41d8552370e722dfbd08d4.tar.gz pyramid-9904b3546478e3299e41d8552370e722dfbd08d4.tar.bz2 pyramid-9904b3546478e3299e41d8552370e722dfbd08d4.zip | |
- Fix deprecated example showing ``chameleon_zpt`` API call in testing
narrative chapter.
| -rw-r--r-- | CHANGES.txt | 3 | ||||
| -rw-r--r-- | TODO.txt | 3 | ||||
| -rw-r--r-- | docs/narr/testing.rst | 106 |
3 files changed, 56 insertions, 56 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 32d145c9f..0721a359f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -15,6 +15,9 @@ Documentation - Merged caseman-master narrative editing branch, many wording fixes and extensions. +- Fix deprecated example showing ``chameleon_zpt`` API call in testing + narrative chapter. + Backwards Incompatibilities --------------------------- @@ -6,9 +6,6 @@ Must-Have (before 1.0) - Write a "Whats New" (delta from BFG 1.3) -- Fix deprecated example showing ``chameleon_zpt`` API call in testing - narrative chapter. - - Use a commit veto when configuring repoze.tm2 in paster templates for non-1X, 2X, or 3X responses. diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index 0968ad229..e166962f2 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -190,27 +190,29 @@ function. .. code-block:: python :linenos: + from pyramid.security import has_permission + from pyramid.exceptions import Forbidden + def view_fn(request): - from pyramid.chameleon_zpt import render_template_to_response - if 'say' in request.params: - return render_template_to_response('templates/submitted.pt', - say=request.params['say']) - return render_template_to_response('templates/show.pt', say='Hello') - -Without invoking any startup code or using the testing API, an attempt to run -this view function in a unit test will result in an error. When a -:app:`Pyramid` application starts normally, it will populate a -: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. with an -:meth:`pyramid.config.Configurator.add_view` :term:`configuration -declaration`), like when you invoke application code via a unit test, -:app:`Pyramid` API functions will tend to fail. + if not has_permission('edit', request.context, request): + raise Forbidden + return {'greeting':'hello'} + +Without doing anything special during a unit test, the call to +:func:`pyramid.security.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 :term:`configuration +declaration` calls made against a :term:`Configurator`. 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 code in this +view function that raises :exc:`Forbidden`? The testing API provided by :app:`Pyramid` allows you to simulate various application registry registrations for use under a unit testing framework without needing to invoke the actual application configuration implied by its -``run.py``. For example, if you wanted to test the above ``view_fn`` +``main`` function. For example, if you wanted to test the above ``view_fn`` (assuming it lived in the package named ``my.package``), you could write a :class:`unittest.TestCase` that used the testing API. @@ -227,61 +229,59 @@ without needing to invoke the actual application configuration implied by its def tearDown(self): testing.tearDown() - def test_view_fn_not_submitted(self): + def test_view_fn_forbidden(self): + from pyramid.exceptions import Forbidden from my.package import view_fn - renderer = self.config.testing_add_renderer('templates/show.pt') + self.config.testing_securitypolicy(userid='hank', + permissive=False) request = testing.DummyRequest() - response = view_fn(request) - renderer.assert_(say='Hello') + request.context = testing.DummyResource() + self.assertRaises(Forbidden, view_fn, request) - def test_view_fn_submitted(self): + def test_view_fn_allowed(self): + from pyramid.exceptions import Forbidden from my.package import view_fn - renderer = self.config.testing_add_renderer( - 'templates/submitted.pt') + self.config.testing_securitypolicy(userid='hank', + permissive=True) request = testing.DummyRequest() - request.params['say'] = 'Yo' + request.context = testing.DummyResource() response = view_fn(request) - renderer.assert_(say='Yo') - + self.assertEqual(response, {'greeting':'hello'}) + In the above example, we create a ``MyTest`` test case that inherits from :mod:`unittest.TestCase`. If it's in our :app:`Pyramid` application, it will be found when ``setup.py test`` is run. It has two test methods. -The first test method, ``test_view_fn_not_submitted`` tests the ``view_fn`` -function in the case that no "form" values (represented by request.params) -have been submitted. Its first line registers a "dummy template renderer" -named ``templates/show.pt`` via the -:meth:`pyramid.config.Configurator.testing_add_renderer` method; this method -returns a :class:`pyramid.testing.DummyTemplateRenderer` instance which we -hang on to for later. +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. We then create a :class:`pyramid.testing.DummyRequest` object which simulates a WebOb request object API. A :class:`pyramid.testing.DummyRequest` is a request object that requires less setup than a "real" :app:`Pyramid` request. We call the function being tested with the manufactured request. When the -function is called, :func:`pyramid.chameleon_zpt.render_template_to_response` -will call the "dummy" template renderer object instead of the real template -renderer object. When the dummy renderer is called, it will set attributes -on itself corresponding to the non-path keyword arguments provided to the -:func:`pyramid.chameleon_zpt.render_template_to_response` function. We check -that the ``say`` parameter sent into the template rendering function was -``Hello`` in this specific example. The ``assert_`` method of the renderer -we've created will raise an :exc:`AssertionError` if the value passed to the -renderer as ``say`` does not equal ``Hello`` (any number of keyword arguments -are supported). - -The second test method, named ``test_view_fn_submitted`` tests the alternate -case, where the ``say`` form value has already been set in the request and -performs a similar template registration and assertion. We assert at the end -of this that the renderer's ``say`` attribute is ``Yo``, as this is what is -expected of the view function in the branch it's testing. +function is called, :func:`pyramid.security.has_permission` will call the +"dummy" authentication policy we've registered through +:meth:`pyramid.config.Configuration.testing_securitypolicy`, which denies +access. We check that the view function raises a :exc:`Forbidden` error. + +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. 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. 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. +``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, |
