diff options
| author | Christoph Zwerschke <cito@online.de> | 2016-04-19 20:07:12 +0200 |
|---|---|---|
| committer | Christoph Zwerschke <cito@online.de> | 2016-04-19 20:07:12 +0200 |
| commit | 3629c49e46207ff5162a82883c14937e6ef4c186 (patch) | |
| tree | 1306181202cb8313f16080789f5b9ab1eeb61d53 /docs/quick_tutorial/unit_testing.rst | |
| parent | 804ba0b2f434781e77d2b5191f1cd76a490f6610 (diff) | |
| parent | 6c16fb020027fac47e4d2e335cd9e264dba8aa3b (diff) | |
| download | pyramid-3629c49e46207ff5162a82883c14937e6ef4c186.tar.gz pyramid-3629c49e46207ff5162a82883c14937e6ef4c186.tar.bz2 pyramid-3629c49e46207ff5162a82883c14937e6ef4c186.zip | |
Merge remote-tracking branch 'refs/remotes/Pylons/master'
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..56fd2b297 --- /dev/null +++ b/docs/quick_tutorial/unit_testing.rst @@ -0,0 +1,117 @@ +.. _qtut_unit_testing: + +============================= +05: Unit Tests and ``pytest`` +============================= + +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 :ref:`pytest <pytest:features>`, have +extended this framework with alternative test runners that provide more +convenience and functionality. The Pyramid developers use ``pytest``, which +we'll 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 `pytest-cov +<http://pytest-cov.readthedocs.org/en/latest/>`_ for another section. + + +Objectives +========== + +- Write unit tests that ensure the quality of our code. + +- Install a Python package (``pytest``) which helps in our testing. + + +Steps +===== + +#. First we copy the results of the previous step, as well as install the + ``pytest`` package: + + .. code-block:: bash + + $ cd ..; cp -r debugtoolbar unit_testing; cd unit_testing + $ $VENV/bin/pip install -e . + $ $VENV/bin/pip install pytest + +#. 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 + + + $ $VENV/bin/py.test tutorial/tests.py -q + . + 1 passed in 0.14 seconds + + +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 expect. + +The ``tests.TutorialViewTests.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 ``py.test`` 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:`testing_chapter` |
