|
| 1 | +=========================== |
| 2 | +Testing Django applications |
| 3 | +=========================== |
| 4 | + |
| 5 | +**New in Django development version**. |
| 6 | + |
| 7 | +.. XXX insert quick introduction to testing (and why you'd want to do it) |
| 8 | + |
| 9 | +.. note:: |
| 10 | + |
| 11 | + This testing framework is currently under development, and may change |
| 12 | + slightly before the next official Django release. |
| 13 | + |
| 14 | + (That's *no* excuse not to write tests, though!) |
| 15 | + |
| 16 | +Writing tests |
| 17 | +============= |
| 18 | + |
| 19 | +Tests in Django come in two forms: doctests and unit tests. |
| 20 | + |
| 21 | +Writing doctests |
| 22 | +---------------- |
| 23 | + |
| 24 | +Doctests use Python's standard doctest_ module, which searches for tests in |
| 25 | +your docstrings. Django's test runner looks for doctests in your ``models.py`` |
| 26 | +file, and executes any that it finds. |
| 27 | + |
| 28 | +.. admonition:: What's a **docstring**? |
| 29 | + |
| 30 | + A good explanation of docstrings (and some guidlines for using them |
| 31 | + effectively) can be found in :PEP:`257`: |
| 32 | + |
| 33 | + A docstring is a string literal that occurs as the first statement in |
| 34 | + a module, function, class, or method definition. Such a docstring |
| 35 | + becomes the ``__doc__`` special attribute of that object. |
| 36 | + |
| 37 | + Since tests often make great documentation, doctest lets you put your |
| 38 | + tests directly in your docstrings. |
| 39 | + |
| 40 | +You can put doctest strings on any object in your ``models.py``, but it's |
| 41 | +common practice to put application-level doctests in the module docstring, and |
| 42 | +model-level doctests in the docstring for each model. |
| 43 | + |
| 44 | +For example:: |
| 45 | + |
| 46 | + from django.db import model |
| 47 | + |
| 48 | + class Animal(models.Model): |
| 49 | + """ |
| 50 | + An animal that knows how to make noise |
| 51 | + |
| 52 | + # Create some animals |
| 53 | + >>> lion = Animal.objects.create(name="lion", sound="roar") |
| 54 | + >>> cat = Animal.objects.create(name="cat", sound="meow") |
| 55 | + |
| 56 | + # Make 'em speak |
| 57 | + >>> lion.speak() |
| 58 | + 'The lion says "roar"' |
| 59 | + >>> cat.speak() |
| 60 | + 'The cat says "meow"' |
| 61 | + """ |
| 62 | + |
| 63 | + name = models.CharField(maxlength=20) |
| 64 | + sound = models.CharField(maxlength=20) |
| 65 | + |
| 66 | + def speak(self): |
| 67 | + return 'The %s says "%s"' % (self.name, self.sound) |
| 68 | + |
| 69 | +When you `run your tests`_, the test utility will find this docstring, notice |
| 70 | +that portions of it look like an interactive Python session, and execute those |
| 71 | +lines while checking that the results match. |
| 72 | + |
| 73 | +For more details about how doctest works, see the `standard library |
| 74 | +documentation for doctest`_ |
| 75 | + |
| 76 | +.. _doctest: http://docs.python.org/lib/module-doctest.html |
| 77 | +.. _standard library documentation for doctest: doctest_ |
| 78 | + |
| 79 | +Writing unittests |
| 80 | +----------------- |
| 81 | + |
| 82 | +Like doctests, Django's unit tests use a standard library module: unittest_. |
| 83 | +Django's test runner looks for unit test cases in a ``tests.py`` file in your |
| 84 | +app (i.e. in the same directory as your ``models.py`` file). |
| 85 | + |
| 86 | +An equivalent unittest test case for the above example would look like:: |
| 87 | + |
| 88 | + import unittest |
| 89 | + from myapp.models import Animal |
| 90 | + |
| 91 | + class AnimalTestCase(unittest.TestCase): |
| 92 | + |
| 93 | + def setUp(self): |
| 94 | + self.lion = Animal.objects.create(name="lion", sound="roar") |
| 95 | + self.cat = Animal.objects.create(name="cat", sound="meow") |
| 96 | + |
| 97 | + def testSpeaking(self): |
| 98 | + self.assertEquals(self.lion.speak(), 'The lion says "roar"') |
| 99 | + self.assertEquals(self.cat.speak(), 'The cat says "meow"') |
| 100 | + |
| 101 | +When you `run your tests`_, the test utility will find all the test cases |
| 102 | +(that is, subclasses of ``unittest.TestCase``) in ``tests.py``, automatically |
| 103 | +build a test suite out of those test cases, and run that suite. |
| 104 | + |
| 105 | +For more details about ``unittest``, see the `standard library unittest |
| 106 | +documentation`_. |
| 107 | + |
| 108 | +.. _unittest: http://docs.python.org/lib/module-unittest.html |
| 109 | +.. _standard library unittest documentation: unittest_ |
| 110 | +.. _run your tests: `Running tests`_ |
| 111 | + |
| 112 | +Which should I use? |
| 113 | +------------------- |
| 114 | + |
| 115 | +Choosing a test framework is often contentious, so Django simply supports |
| 116 | +both of the standard Python test frameworks. Choosing one is up to each |
| 117 | +developer's personal tastes; each is supported equally. Since each test |
| 118 | +system has different benefits, the best approach is probably to use both |
| 119 | +together, picking the test system to match the type of tests you need to |
| 120 | +write. |
| 121 | + |
| 122 | +For developers new to testing, however, this choice can seem |
| 123 | +confusing, so here are a few key differences to help you decide weather |
| 124 | +doctests or unit tests are right for you. |
| 125 | + |
| 126 | +If you've been using Python for a while, ``doctest`` will probably feel more |
| 127 | +"pythonic". It's designed to make writing tests as easy as possible, so |
| 128 | +there's no overhead of writing classes or methods; you simply put tests in |
| 129 | +docstrings. This gives the added advantage of given your modules automatic |
| 130 | +documentation -- well-written doctests can kill both the documentation and the |
| 131 | +testing bird with a single stone. |
| 132 | + |
| 133 | +For developers just getting started with testing, using doctests will probably |
| 134 | +get you started faster. |
| 135 | + |
| 136 | +The ``unittest`` framework will probably feel very familiar to developers |
| 137 | +coming from Java. Since ``unittest`` is inspired by Java's JUnit, if |
| 138 | +you've used testing frameworks in other languages that similarly were |
| 139 | +inspired by JUnit, ``unittest`` should also feel pretty familiar. |
| 140 | + |
| 141 | +Since ``unittest`` is organized around classes and methods, if you need |
| 142 | +to write a bunch of tests that all share similar code, you can easily use |
| 143 | +subclass to abstract common tasks; this makes test code shorter and cleaner. |
| 144 | +There's also support for explicit setup and/or cleanup routines, which give |
| 145 | +you a high level of control over the environment your test cases run in. |
| 146 | + |
| 147 | +Again, remember that you can use both systems side-by-side (even in the same |
| 148 | +app). In the end, most projects will eventually end up using both; each shines |
| 149 | +in different circumstances. |
| 150 | + |
| 151 | +Running tests |
| 152 | +============= |
| 153 | + |
| 154 | +Run your tests using your project's ``manage.py`` utility:: |
| 155 | + |
| 156 | + $ ./manage.py test |
| 157 | + |
| 158 | +You'll see a bunch of text flow by as the test database is created, models are |
| 159 | +initialized, and your tests are run. If everything goes well, at the end |
| 160 | +you'll see:: |
| 161 | + |
| 162 | + ---------------------------------------------------------------------- |
| 163 | + Ran 22 tests in 0.221s |
| 164 | + |
| 165 | + OK |
| 166 | + |
| 167 | +If there are test failures, however, you'll see full details about what tests |
| 168 | +failed:: |
| 169 | + |
| 170 | + ====================================================================== |
| 171 | + FAIL: Doctest: ellington.core.throttle.models |
| 172 | + ---------------------------------------------------------------------- |
| 173 | + Traceback (most recent call last): |
| 174 | + File "/dev/django/test/doctest.py", line 2153, in runTest |
| 175 | + raise self.failureException(self.format_failure(new.getvalue())) |
| 176 | + AssertionError: Failed doctest test for myapp.models |
| 177 | + File "/dev/myapp/models.py", line 0, in models |
| 178 | + |
| 179 | + ---------------------------------------------------------------------- |
| 180 | + File "/dev/myapp/models.py", line 14, in myapp.models |
| 181 | + Failed example: |
| 182 | + throttle.check("actor A", "action one", limit=2, hours=1) |
| 183 | + Expected: |
| 184 | + True |
| 185 | + Got: |
| 186 | + False |
| 187 | + |
| 188 | + ---------------------------------------------------------------------- |
| 189 | + Ran 2 tests in 0.048s |
| 190 | + |
| 191 | + FAILED (failures=1) |
| 192 | + |
0 commit comments