diff options
| author | Paul Everitt <paul@agendaless.com> | 2013-09-13 16:52:14 -0400 |
|---|---|---|
| committer | Paul Everitt <paul@agendaless.com> | 2013-09-13 16:52:14 -0400 |
| commit | b1b92284f496800a4dfd2cea72cb9be07ba8661c (patch) | |
| tree | 9dfa72427fd6aa0a3a7aaba72be4a4e49380ee26 /docs/quick_tutorial/unit_testing.rst | |
| parent | 1d04f8f0b483b8d595f5ada24ae5108affe80160 (diff) | |
| download | pyramid-b1b92284f496800a4dfd2cea72cb9be07ba8661c.tar.gz pyramid-b1b92284f496800a4dfd2cea72cb9be07ba8661c.tar.bz2 pyramid-b1b92284f496800a4dfd2cea72cb9be07ba8661c.zip | |
First cut at import of quick tutorial.
Diffstat (limited to 'docs/quick_tutorial/unit_testing.rst')
| -rw-r--r-- | docs/quick_tutorial/unit_testing.rst | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/docs/quick_tutorial/unit_testing.rst b/docs/quick_tutorial/unit_testing.rst new file mode 100644 index 000000000..cc9dfcc8a --- /dev/null +++ b/docs/quick_tutorial/unit_testing.rst @@ -0,0 +1,117 @@ +=========================== +05: Unit Tests and ``nose`` +=========================== + +Provide unit testing for our project's Python code. + +Background +========== + +As the mantra says, "Untested code is broken code." The Python +community has had a long culture of writing test scripts which ensure +that your code works correctly as you write it and maintain it in the +future. Pyramid has always had a deep commitment to testing, +with 100% test coverage from the earliest pre-releases. + +Python includes a +:ref:`unit testing framework <python:unittest-minimal-example>` in its +standard library. Over the years a number of Python projects, such as +`nose <https://pypi.python.org/pypi/nose/>`_, have extended this +framework with alternative test runners that provide more convenience +and functionality. The Pyramid developers use ``nose``, which we'll thus +use in this tutorial. + +Don't worry, this tutorial won't be pedantic about "test-driven +development" (TDD.) We'll do just enough to ensure that, in each step, +we haven't majorly broken the code. As you're writing your code you +might find this more convenient than changing to your browser +constantly and clicking reload. + +We'll also leave discussion of +`coverage <https://pypi.python.org/pypi/coverage>`_ for another section. + +Objectives +========== + +- Write unit tests that ensure the quality of our code + +- Install a Python package (``nose``) which helps in our testing + +Steps +===== + +#. First we copy the results of the previous step, as well as install + the ``nose`` package: + + .. code-block:: bash + + (env27)$ cd ..; cp -r debugtoolbar unit_testing; cd unit_testing + (env27)$ python setup.py develop + (env27)$ easy_install nose + +#. Now we write a simple unit test in ``unit_testing/tutorial/tests.py``: + + .. literalinclude:: unit_testing/tutorial/tests.py + :linenos: + +#. Now run the tests: + + .. code-block:: bash + + + (env27)$ nosetests tutorial + . + ---------------------------------------------------------------------- + Ran 1 test in 0.141s + + OK + +Analysis +======== + +Our ``tests.py`` imports the Python standard unit testing framework. To +make writing Pyramid-oriented tests more convenient, Pyramid supplies +some ``pyramid.testing`` helpers which we use in the test setup and +teardown. Our one test imports the view, makes a dummy request, and sees +if the view returns what we expected. + +The ``tests.HelloWorldViewTests.test_hello_world`` test is a small +example of a unit test. First, we import the view inside each test. Why +not import at the top, like in normal Python code? Because imports can +cause effects that break a test. We'd like our tests to be in *units*, +hence the name *unit* testing. Each test should isolate itself to the +correct degree. + +Our test then makes a fake incoming web request, then calls our Pyramid +view. We test the HTTP status code on the response to make sure it +matches our expectations. + +Note that our use of ``pyramid.testing.setUp()`` and +``pyramid.testing.tearDown()`` aren't actually necessary here; they are only +necessary when your test needs to make use of the ``config`` object (it's a +Configurator) to add stuff to the configuration state before calling the view. + +Extra Credit +============ + +#. Change the test to assert that the response status code should be + ``404`` (meaning, not found.) Run ``nosetests`` again. Read the + error report and see if you can decipher what it is telling you. + +#. As a more realistic example, put the ``tests.py`` back as you found + it and put an error in your view, such as a reference to a + non-existing variable. Run the tests and see how this is more + convenient than reloading your browser and going back to your code. + +#. Finally, for the most realistic test, read about Pyramid ``Response`` + objects and see how to change the response code. Run the tests and + see how testing confirms the "contract" that your code claims to + support. + +#. How could we add a unit test assertion to test the HTML value of the + response body? + +#. Why do we import the ``hello_world`` view function *inside* the + ``test_hello_world`` method instead of at the top of the module? + +.. seealso:: See Also: :ref:`pyramid:testing_chapter` |
