From 0866dc171582125bb9d81a640a70d907553e9d54 Mon Sep 17 00:00:00 2001 From: Timo Graham Date: Sun, 16 Jan 2011 19:27:23 +0000 Subject: [PATCH] [1.2.X] Fixed #13628 - Discourage the use of doctests; thanks d0ugal for the suggestion. Backport of r15227 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@15228 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- docs/topics/testing.txt | 152 ++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 77 deletions(-) diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt index 665bddd756..df6baa2751 100644 --- a/docs/topics/testing.txt +++ b/docs/topics/testing.txt @@ -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,58 @@ 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.assertEquals(my_func(a, 0), 'larry') - self.assertEquals(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. +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 `, 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 +133,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 +151,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,57 +197,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 standard library module: unittest_. -This module uses a different way of defining tests, taking a class-based -approach. - -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:: - - 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.assertEquals(self.lion.speak(), 'The lion says "roar"') - self.assertEquals(self.cat.speak(), 'The cat says "meow"') - -When you :ref:`run your 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? ------------------- @@ -214,10 +212,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 @@ -231,9 +231,7 @@ you: routines, which give you a high level of control over the environment in which your test cases are run. -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. + * If you're writing tests for Django itself, you should use ``unittest``. .. _running-tests: @@ -676,7 +674,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. .. versionadded:: 1.1 @@ -1533,7 +1531,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