0
0
mirror of https://github.com/django/django.git synced 2024-11-29 22:56:46 +01:00

Fixed #13628 - Discourage the use of doctests; thanks d0ugal for the suggestion.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15227 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Timo Graham 2011-01-16 19:22:36 +00:00
parent f89f1c8acb
commit 5fd93e1c36

View File

@ -35,6 +35,17 @@ There are two primary ways to write tests with Django, corresponding to the
two test frameworks that ship in the Python standard library. The two
frameworks are:
* **Unit tests** -- tests that are expressed as methods on a Python class
that subclasses ``unittest.TestCase``. For example::
import unittest
class MyFuncTestCase(unittest.TestCase):
def testBasic(self):
a = ['larry', 'curly', 'moe']
self.assertEqual(my_func(a, 0), 'larry')
self.assertEqual(my_func(a, 1), 'curly')
* **Doctests** -- tests that are embedded in your functions' docstrings and
are written in a way that emulates a session of the Python interactive
interpreter. For example::
@ -49,21 +60,87 @@ frameworks are:
"""
return a_list[idx]
* **Unit tests** -- tests that are expressed as methods on a Python class
that subclasses ``unittest.TestCase``. For example::
We'll discuss choosing the appropriate test framework later, however, most
experienced developers prefer unit tests. You can also use any *other* Python
test framework, as we'll explain in a bit.
import unittest
Writing unit tests
------------------
class MyFuncTestCase(unittest.TestCase):
def testBasic(self):
a = ['larry', 'curly', 'moe']
self.assertEqual(my_func(a, 0), 'larry')
self.assertEqual(my_func(a, 1), 'curly')
Django's unit tests use a Python standard library module: unittest_. This
module defines tests in class-based approach.
You can choose the test framework you like, depending on which syntax you
prefer, or you can mix and match, using one framework for some of your code and
the other framework for other code. You can also use any *other* Python test
frameworks, as we'll explain in a bit.
.. admonition:: unittest2
.. versionchanged:: 1.3
Python 2.7 introduced some major changes to the unittest library,
adding some extremely useful features. To ensure that every Django
project can benefit from these new features, Django ships with a
copy of unittest2_, a copy of the Python 2.7 unittest library,
backported for Python 2.4 compatibility.
To access this library, Django provides the
``django.utils.unittest`` module alias. If you are using Python
2.7, or you have installed unittest2 locally, Django will map the
alias to the installed version of the unittest library. Otherwise,
Django will use it's own bundled version of unittest2.
To use this alias, simply use::
from django.utils import unittest
wherever you would have historically used::
import unittest
If you want to continue to use the base unittest libary, you can --
you just won't get any of the nice new unittest2 features.
.. _unittest2: http://pypi.python.org/pypi/unittest2
For a given Django application, the test runner looks for unit tests in two
places:
* The ``models.py`` file. The test runner looks for any subclass of
``unittest.TestCase`` in this module.
* A file called ``tests.py`` in the application directory -- i.e., the
directory that holds ``models.py``. Again, the test runner looks for any
subclass of ``unittest.TestCase`` in this module.
Here is an example ``unittest.TestCase`` subclass::
from django.utils import unittest
from myapp.models import Animal
class AnimalTestCase(unittest.TestCase):
def setUp(self):
self.lion = Animal.objects.create(name="lion", sound="roar")
self.cat = Animal.objects.create(name="cat", sound="meow")
def testSpeaking(self):
self.assertEqual(self.lion.speak(), 'The lion says "roar"')
self.assertEqual(self.cat.speak(), 'The cat says "meow"')
When you :ref:`run your tests <running-tests>`, the default behavior of the
test utility is to find all the test cases (that is, subclasses of
``unittest.TestCase``) in ``models.py`` and ``tests.py``, automatically build a
test suite out of those test cases, and run that suite.
There is a second way to define the test suite for a module: if you define a
function called ``suite()`` in either ``models.py`` or ``tests.py``, the
Django test runner will use that function to construct the test suite for that
module. This follows the `suggested organization`_ for unit tests. See the
Python documentation for more details on how to construct a complex test
suite.
For more details about ``unittest``, see the `standard library unittest
documentation`_.
.. _unittest: http://docs.python.org/library/unittest.html
.. _standard library unittest documentation: unittest_
.. _suggested organization: http://docs.python.org/library/unittest.html#organizing-tests
Writing doctests
----------------
@ -85,14 +162,14 @@ read Python's official documentation for the details.
For example, this function has a docstring that describes what it does::
def add_two(num):
"Return the result of adding two to the provided number."
return num + 2
"Return the result of adding two to the provided number."
return num + 2
Because tests often make great documentation, putting tests directly in
your docstrings is an effective way to document *and* test your code.
For a given Django application, the test runner looks for doctests in two
places:
As with unit tests, for a given Django application, the test runner looks for
doctests in two places:
* The ``models.py`` file. You can define module-level doctests and/or a
doctest for individual models. It's common practice to put
@ -103,7 +180,8 @@ places:
directory that holds ``models.py``. This file is a hook for any and all
doctests you want to write that aren't necessarily related to models.
Here is an example model doctest::
This example doctest is equivalent to the example given in the unittest section
above::
# models.py
@ -148,86 +226,6 @@ documentation for doctest`_.
.. _doctest: http://docs.python.org/library/doctest.html
.. _standard library documentation for doctest: doctest_
Writing unit tests
------------------
Like doctests, Django's unit tests use a Python standard library
module: unittest_. This module uses a different way of defining tests,
taking a class-based approach.
.. admonition:: unittest2
.. versionchanged:: 1.3
Python 2.7 introduced some major changes to the unittest library,
adding some extremely useful features. To ensure that every Django
project can benefit from these new features, Django ships with a
copy of unittest2_, a copy of the Python 2.7 unittest library,
backported for Python 2.4 compatibility.
To access this library, Django provides the
``django.utils.unittest`` module alias. If you are using Python
2.7, or you have installed unittest2 locally, Django will map the
alias to the installed version of the unittest library. Otherwise,
Django will use it's own bundled version of unittest2.
To use this alias, simply use::
from django.utils import unittest
wherever you would have historically used::
import unittest
If you want to continue to use the base unittest libary, you can --
you just won't get any of the nice new unittest2 features.
.. _unittest2: http://pypi.python.org/pypi/unittest2
As with doctests, for a given Django application, the test runner looks for
unit tests in two places:
* The ``models.py`` file. The test runner looks for any subclass of
``unittest.TestCase`` in this module.
* A file called ``tests.py`` in the application directory -- i.e., the
directory that holds ``models.py``. Again, the test runner looks for any
subclass of ``unittest.TestCase`` in this module.
This example ``unittest.TestCase`` subclass is equivalent to the example given
in the doctest section above::
from django.utils import unittest
from myapp.models import Animal
class AnimalTestCase(unittest.TestCase):
def setUp(self):
self.lion = Animal.objects.create(name="lion", sound="roar")
self.cat = Animal.objects.create(name="cat", sound="meow")
def testSpeaking(self):
self.assertEqual(self.lion.speak(), 'The lion says "roar"')
self.assertEqual(self.cat.speak(), 'The cat says "meow"')
When you :ref:`run your tests <running-tests>`, the default behavior of the
test utility is to find all the test cases (that is, subclasses of
``unittest.TestCase``) in ``models.py`` and ``tests.py``, automatically build a
test suite out of those test cases, and run that suite.
There is a second way to define the test suite for a module: if you define a
function called ``suite()`` in either ``models.py`` or ``tests.py``, the
Django test runner will use that function to construct the test suite for that
module. This follows the `suggested organization`_ for unit tests. See the
Python documentation for more details on how to construct a complex test
suite.
For more details about ``unittest``, see the `standard library unittest
documentation`_.
.. _unittest: http://docs.python.org/library/unittest.html
.. _standard library unittest documentation: unittest_
.. _suggested organization: http://docs.python.org/library/unittest.html#organizing-tests
Which should I use?
-------------------
@ -244,10 +242,12 @@ you:
more "pythonic". It's designed to make writing tests as easy as possible,
so it requires no overhead of writing classes or methods. You simply put
tests in docstrings. This has the added advantage of serving as
documentation (and correct documentation, at that!).
If you're just getting started with testing, using doctests will probably
get you started faster.
documentation (and correct documentation, at that!). However, while
doctests are good for some simple example code, they are not very good if
you want to produce either high quality, comprehensive tests or high
quality documentation. Test failures are often difficult to debug
as it can be unclear exactly why the test failed. Thus, doctests should
generally be avoided and used primarily for documentation examples only.
* The ``unittest`` framework will probably feel very familiar to developers
coming from Java. ``unittest`` is inspired by Java's JUnit, so you'll
@ -263,10 +263,6 @@ you:
* If you're writing tests for Django itself, you should use ``unittest``.
Again, remember that you can use both systems side-by-side (even in the same
app). In the end, most projects will eventually end up using both. Each shines
in different circumstances.
.. _running-tests:
Running tests
@ -710,7 +706,7 @@ arguments at time of construction:
... HTTP_X_REQUESTED_WITH='XMLHttpRequest')
...will send the HTTP header ``HTTP_X_REQUESTED_WITH`` to the
details view, which is a good way to test code paths that use the
details view, which is a good way to test code paths that use the
:meth:`django.http.HttpRequest.is_ajax()` method.
If you already have the GET arguments in URL-encoded form, you can
@ -1715,7 +1711,7 @@ set up, execute and tear down the test suite.
.. method:: DjangoTestSuiteRunner.suite_result(suite, result, **kwargs)
Computes and returns a return code based on a test suite, and the result
from that test suite.
from that test suite.
Testing utilities