diff --git a/docs/django-admin.txt b/docs/django-admin.txt index eb7b2dccd6..b8bf2cef76 100644 --- a/docs/django-admin.txt +++ b/docs/django-admin.txt @@ -292,6 +292,13 @@ this command to install the default apps. If you're installing the ``django.contrib.auth`` application, ``syncdb`` will give you the option of creating a superuser immediately. +test +---- + +Discover and run tests for all installed models. See `Testing Django applications`_ for more information. + +.. _testing django applications: ../testing/ + validate -------- diff --git a/docs/testing.txt b/docs/testing.txt new file mode 100644 index 0000000000..7e896b635b --- /dev/null +++ b/docs/testing.txt @@ -0,0 +1,192 @@ +=========================== +Testing Django applications +=========================== + +**New in Django development version**. + +.. XXX insert quick introduction to testing (and why you'd want to do it) + +.. note:: + + This testing framework is currently under development, and may change + slightly before the next official Django release. + + (That's *no* excuse not to write tests, though!) + +Writing tests +============= + +Tests in Django come in two forms: doctests and unit tests. + +Writing doctests +---------------- + +Doctests use Python's standard doctest_ module, which searches for tests in +your docstrings. Django's test runner looks for doctests in your ``models.py`` +file, and executes any that it finds. + +.. admonition:: What's a **docstring**? + + A good explanation of docstrings (and some guidlines for using them + effectively) can be found in :PEP:`257`: + + A docstring is a string literal that occurs as the first statement in + a module, function, class, or method definition. Such a docstring + becomes the ``__doc__`` special attribute of that object. + + Since tests often make great documentation, doctest lets you put your + tests directly in your docstrings. + +You can put doctest strings on any object in your ``models.py``, but it's +common practice to put application-level doctests in the module docstring, and +model-level doctests in the docstring for each model. + +For example:: + + from django.db import model + + class Animal(models.Model): + """ + An animal that knows how to make noise + + # Create some animals + >>> lion = Animal.objects.create(name="lion", sound="roar") + >>> cat = Animal.objects.create(name="cat", sound="meow") + + # Make 'em speak + >>> lion.speak() + 'The lion says "roar"' + >>> cat.speak() + 'The cat says "meow"' + """ + + name = models.CharField(maxlength=20) + sound = models.CharField(maxlength=20) + + def speak(self): + return 'The %s says "%s"' % (self.name, self.sound) + +When you `run your tests`_, the test utility will find this docstring, notice +that portions of it look like an interactive Python session, and execute those +lines while checking that the results match. + +For more details about how doctest works, see the `standard library +documentation for doctest`_ + +.. _doctest: http://docs.python.org/lib/module-doctest.html +.. _standard library documentation for doctest: doctest_ + +Writing unittests +----------------- + +Like doctests, Django's unit tests use a standard library module: unittest_. +Django's test runner looks for unit test cases in a ``tests.py`` file in your +app (i.e. in the same directory as your ``models.py`` file). + +An equivalent unittest test case for the above example would look like:: + + 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 `run your tests`_, the test utility will find all the test cases +(that is, subclasses of ``unittest.TestCase``) in ``tests.py``, automatically +build a test suite out of those test cases, and run that suite. + +For more details about ``unittest``, see the `standard library unittest +documentation`_. + +.. _unittest: http://docs.python.org/lib/module-unittest.html +.. _standard library unittest documentation: unittest_ +.. _run your tests: `Running tests`_ + +Which should I use? +------------------- + +Choosing a test framework is often contentious, so Django simply supports +both of the standard Python test frameworks. Choosing one is up to each +developer's personal tastes; each is supported equally. Since each test +system has different benefits, the best approach is probably to use both +together, picking the test system to match the type of tests you need to +write. + +For developers new to testing, however, this choice can seem +confusing, so here are a few key differences to help you decide weather +doctests or unit tests are right for you. + +If you've been using Python for a while, ``doctest`` will probably feel more +"pythonic". It's designed to make writing tests as easy as possible, so +there's no overhead of writing classes or methods; you simply put tests in +docstrings. This gives the added advantage of given your modules automatic +documentation -- well-written doctests can kill both the documentation and the +testing bird with a single stone. + +For developers just getting started with testing, using doctests will probably +get you started faster. + +The ``unittest`` framework will probably feel very familiar to developers +coming from Java. Since ``unittest`` is inspired by Java's JUnit, if +you've used testing frameworks in other languages that similarly were +inspired by JUnit, ``unittest`` should also feel pretty familiar. + +Since ``unittest`` is organized around classes and methods, if you need +to write a bunch of tests that all share similar code, you can easily use +subclass to abstract common tasks; this makes test code shorter and cleaner. +There's also support for explicit setup and/or cleanup routines, which give +you a high level of control over the environment your test cases run in. + +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 +============= + +Run your tests using your project's ``manage.py`` utility:: + + $ ./manage.py test + +You'll see a bunch of text flow by as the test database is created, models are +initialized, and your tests are run. If everything goes well, at the end +you'll see:: + + ---------------------------------------------------------------------- + Ran 22 tests in 0.221s + + OK + +If there are test failures, however, you'll see full details about what tests +failed:: + + ====================================================================== + FAIL: Doctest: ellington.core.throttle.models + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "/dev/django/test/doctest.py", line 2153, in runTest + raise self.failureException(self.format_failure(new.getvalue())) + AssertionError: Failed doctest test for myapp.models + File "/dev/myapp/models.py", line 0, in models + + ---------------------------------------------------------------------- + File "/dev/myapp/models.py", line 14, in myapp.models + Failed example: + throttle.check("actor A", "action one", limit=2, hours=1) + Expected: + True + Got: + False + + ---------------------------------------------------------------------- + Ran 2 tests in 0.048s + + FAILED (failures=1) +