diff options
Diffstat (limited to 'docs/topics/testing')
| -rw-r--r-- | docs/topics/testing/overview.txt | 235 |
1 files changed, 143 insertions, 92 deletions
diff --git a/docs/topics/testing/overview.txt b/docs/topics/testing/overview.txt index fc2b393898..d543099ae6 100644 --- a/docs/topics/testing/overview.txt +++ b/docs/topics/testing/overview.txt @@ -21,17 +21,16 @@ module defines tests using a class-based approach. .. admonition:: unittest2 - Python 2.7 introduced some major changes to the unittest library, + 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.6 compatibility. + copy of unittest2_, a copy of Python 2.7's ``unittest``, backported for + Python 2.6 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 its own bundled version of unittest2. + 2.7, or you have installed ``unittest2`` locally, Django will map the alias + to it. Otherwise, Django will use its own bundled version of ``unittest2``. To use this alias, simply use:: @@ -41,8 +40,8 @@ module defines tests using a class-based approach. import unittest - If you want to continue to use the base unittest library, you can -- - you just won't get any of the nice new unittest2 features. + If you want to continue to use the legacy ``unittest`` library, you can -- + you just won't get any of the nice new ``unittest2`` features. .. _unittest2: http://pypi.python.org/pypi/unittest2 @@ -858,24 +857,46 @@ SimpleTestCase .. class:: SimpleTestCase() -A very thin subclass of :class:`unittest.TestCase`, it extends it with some -basic functionality like: +A thin subclass of :class:`unittest.TestCase`, it extends it with some basic +functionality like: * Saving and restoring the Python warning machinery state. -* Checking that a callable :meth:`raises a certain exception <SimpleTestCase.assertRaisesMessage>`. -* :meth:`Testing form field rendering <SimpleTestCase.assertFieldOutput>`. -* Testing server :ref:`HTML responses for the presence/lack of a given fragment <assertions>`. -* The ability to run tests with :ref:`modified settings <overriding-settings>` +* Some useful assertions like: + + * Checking that a callable :meth:`raises a certain exception + <SimpleTestCase.assertRaisesMessage>`. + * Testing form field :meth:`rendering and error treatment + <SimpleTestCase.assertFieldOutput>`. + * Testing :meth:`HTML responses for the presence/lack of a given fragment + <SimpleTestCase.assertContains>`. + * Verifying that a template :meth:`has/hasn't been used to generate a given + response content <SimpleTestCase.assertTemplateUsed>`. + * Verifying a HTTP :meth:`redirect <SimpleTestCase.assertRedirects>` is + performed by the app. + * Robustly testing two :meth:`HTML fragments <SimpleTestCase.assertHTMLEqual>` + for equality/inequality or :meth:`containment <SimpleTestCase.assertInHTML>`. + * Robustly testing two :meth:`XML fragments <SimpleTestCase.assertXMLEqual>` + for equality/inequality. + * Robustly testing two :meth:`JSON fragments <SimpleTestCase.assertJSONEqual>` + for equality. + +* The ability to run tests with :ref:`modified settings <overriding-settings>`. +* Using the :attr:`~SimpleTestCase.client` :class:`~django.test.client.Client`. +* Custom test-time :attr:`URL maps <SimpleTestCase.urls>`. + +.. versionchanged:: 1.6 + + The latter two features were moved from ``TransactionTestCase`` to + ``SimpleTestCase`` in Django 1.6. If you need any of the other more complex and heavyweight Django-specific features like: -* Using the :attr:`~TestCase.client` :class:`~django.test.client.Client`. * Testing or using the ORM. -* Database :attr:`~TestCase.fixtures`. -* Custom test-time :attr:`URL maps <TestCase.urls>`. +* Database :attr:`~TransactionTestCase.fixtures`. * Test :ref:`skipping based on database backend features <skipping-tests>`. -* The remaining specialized :ref:`assert* <assertions>` methods. +* The remaining specialized :meth:`assert* + <TransactionTestCase.assertQuerysetEqual>` methods. then you should use :class:`~django.test.TransactionTestCase` or :class:`~django.test.TestCase` instead. @@ -1137,9 +1158,9 @@ Test cases features Default test client ~~~~~~~~~~~~~~~~~~~ -.. attribute:: TestCase.client +.. attribute:: SimpleTestCase.client -Every test case in a ``django.test.TestCase`` instance has access to an +Every test case in a ``django.test.*TestCase`` instance has access to an instance of a Django test client. This client can be accessed as ``self.client``. This client is recreated for each test, so you don't have to worry about state (such as cookies) carrying over from one test to another. @@ -1176,10 +1197,10 @@ This means, instead of instantiating a ``Client`` in each test:: Customizing the test client ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. attribute:: TestCase.client_class +.. attribute:: SimpleTestCase.client_class If you want to use a different ``Client`` class (for example, a subclass -with customized behavior), use the :attr:`~TestCase.client_class` class +with customized behavior), use the :attr:`~SimpleTestCase.client_class` class attribute:: from django.test import TestCase @@ -1200,11 +1221,12 @@ attribute:: Fixture loading ~~~~~~~~~~~~~~~ -.. attribute:: TestCase.fixtures +.. attribute:: TransactionTestCase.fixtures A test case for a database-backed Web site isn't much use if there isn't any data in the database. To make it easy to put test data into the database, -Django's custom ``TestCase`` class provides a way of loading **fixtures**. +Django's custom ``TransactionTestCase`` class provides a way of loading +**fixtures**. A fixture is a collection of data that Django knows how to import into a database. For example, if your site has user accounts, you might set up a @@ -1273,7 +1295,7 @@ or by the order of test execution. URLconf configuration ~~~~~~~~~~~~~~~~~~~~~ -.. attribute:: TestCase.urls +.. attribute:: SimpleTestCase.urls If your application provides views, you may want to include tests that use the test client to exercise those views. However, an end user is free to deploy the @@ -1282,9 +1304,9 @@ tests can't rely upon the fact that your views will be available at a particular URL. In order to provide a reliable URL space for your test, -``django.test.TestCase`` provides the ability to customize the URLconf +``django.test.*TestCase`` classes provide the ability to customize the URLconf configuration for the duration of the execution of a test suite. If your -``TestCase`` instance defines an ``urls`` attribute, the ``TestCase`` will use +``*TestCase`` instance defines an ``urls`` attribute, the ``*TestCase`` will use the value of that attribute as the :setting:`ROOT_URLCONF` for the duration of that test. @@ -1307,7 +1329,7 @@ URLconf for the duration of the test case. Multi-database support ~~~~~~~~~~~~~~~~~~~~~~ -.. attribute:: TestCase.multi_db +.. attribute:: TransactionTestCase.multi_db Django sets up a test database corresponding to every database that is defined in the :setting:`DATABASES` definition in your settings @@ -1340,12 +1362,12 @@ This test case will flush *all* the test databases before running Overriding settings ~~~~~~~~~~~~~~~~~~~ -.. method:: TestCase.settings +.. method:: SimpleTestCase.settings For testing purposes it's often useful to change a setting temporarily and revert to the original value after running the testing code. For this use case Django provides a standard Python context manager (see :pep:`343`) -:meth:`~django.test.TestCase.settings`, which can be used like this:: +:meth:`~django.test.SimpleTestCase.settings`, which can be used like this:: from django.test import TestCase @@ -1435,8 +1457,8 @@ MEDIA_ROOT, DEFAULT_FILE_STORAGE Default file storage Emptying the test outbox ~~~~~~~~~~~~~~~~~~~~~~~~ -If you use Django's custom ``TestCase`` class, the test runner will clear the -contents of the test email outbox at the start of each test case. +If you use any of Django's custom ``TestCase`` classes, the test runner will +clear thecontents of the test email outbox at the start of each test case. For more detail on email services during tests, see `Email services`_ below. @@ -1486,8 +1508,22 @@ your test suite. self.assertFieldOutput(EmailField, {'a@a.com': 'a@a.com'}, {'aaa': [u'Enter a valid email address.']}) +.. method:: SimpleTestCase.assertFormError(response, form, field, errors, msg_prefix='') + + Asserts that a field on a form raises the provided list of errors when + rendered on the form. + + ``form`` is the name the ``Form`` instance was given in the template + context. + + ``field`` is the name of the field on the form to check. If ``field`` + has a value of ``None``, non-field errors (errors you can access via + ``form.non_field_errors()``) will be checked. + + ``errors`` is an error string, or a list of error strings, that are + expected as a result of form validation. -.. method:: TestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False) +.. method:: SimpleTestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='', html=False) Asserts that a ``Response`` instance produced the given ``status_code`` and that ``text`` appears in the content of the response. If ``count`` is @@ -1499,7 +1535,7 @@ your test suite. attribute ordering is not significant. See :meth:`~SimpleTestCase.assertHTMLEqual` for more details. -.. method:: TestCase.assertNotContains(response, text, status_code=200, msg_prefix='', html=False) +.. method:: SimpleTestCase.assertNotContains(response, text, status_code=200, msg_prefix='', html=False) Asserts that a ``Response`` instance produced the given ``status_code`` and that ``text`` does not appears in the content of the response. @@ -1510,22 +1546,7 @@ your test suite. attribute ordering is not significant. See :meth:`~SimpleTestCase.assertHTMLEqual` for more details. -.. method:: TestCase.assertFormError(response, form, field, errors, msg_prefix='') - - Asserts that a field on a form raises the provided list of errors when - rendered on the form. - - ``form`` is the name the ``Form`` instance was given in the template - context. - - ``field`` is the name of the field on the form to check. If ``field`` - has a value of ``None``, non-field errors (errors you can access via - ``form.non_field_errors()``) will be checked. - - ``errors`` is an error string, or a list of error strings, that are - expected as a result of form validation. - -.. method:: TestCase.assertTemplateUsed(response, template_name, msg_prefix='') +.. method:: SimpleTestCase.assertTemplateUsed(response, template_name, msg_prefix='') Asserts that the template with the given name was used in rendering the response. @@ -1539,15 +1560,15 @@ your test suite. with self.assertTemplateUsed(template_name='index.html'): render_to_string('index.html') -.. method:: TestCase.assertTemplateNotUsed(response, template_name, msg_prefix='') +.. method:: SimpleTestCase.assertTemplateNotUsed(response, template_name, msg_prefix='') Asserts that the template with the given name was *not* used in rendering the response. You can use this as a context manager in the same way as - :meth:`~TestCase.assertTemplateUsed`. + :meth:`~SimpleTestCase.assertTemplateUsed`. -.. method:: TestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='') +.. method:: SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='') Asserts that the response return a ``status_code`` redirect status, it redirected to ``expected_url`` (including any GET data), and the final @@ -1557,44 +1578,6 @@ your test suite. ``target_status_code`` will be the url and status code for the final point of the redirect chain. -.. method:: TestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True) - - Asserts that a queryset ``qs`` returns a particular list of values ``values``. - - The comparison of the contents of ``qs`` and ``values`` is performed using - the function ``transform``; by default, this means that the ``repr()`` of - each value is compared. Any other callable can be used if ``repr()`` doesn't - provide a unique or helpful comparison. - - By default, the comparison is also ordering dependent. If ``qs`` doesn't - provide an implicit ordering, you can set the ``ordered`` parameter to - ``False``, which turns the comparison into a Python set comparison. - - .. versionchanged:: 1.6 - - The method now checks for undefined order and raises ``ValueError`` - if undefined order is spotted. The ordering is seen as undefined if - the given ``qs`` isn't ordered and the comparison is against more - than one ordered values. - -.. method:: TestCase.assertNumQueries(num, func, *args, **kwargs) - - Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that - ``num`` database queries are executed. - - If a ``"using"`` key is present in ``kwargs`` it is used as the database - alias for which to check the number of queries. If you wish to call a - function with a ``using`` parameter you can do it by wrapping the call with - a ``lambda`` to add an extra parameter:: - - self.assertNumQueries(7, lambda: my_function(using=7)) - - You can also use this as a context manager:: - - with self.assertNumQueries(2): - Person.objects.create(name="Aaron") - Person.objects.create(name="Daniel") - .. method:: SimpleTestCase.assertHTMLEqual(html1, html2, msg=None) Asserts that the strings ``html1`` and ``html2`` are equal. The comparison @@ -1624,6 +1607,8 @@ your test suite. ``html1`` and ``html2`` must be valid HTML. An ``AssertionError`` will be raised if one of them cannot be parsed. + Output in case of error can be customized with the ``msg`` argument. + .. method:: SimpleTestCase.assertHTMLNotEqual(html1, html2, msg=None) Asserts that the strings ``html1`` and ``html2`` are *not* equal. The @@ -1633,6 +1618,8 @@ your test suite. ``html1`` and ``html2`` must be valid HTML. An ``AssertionError`` will be raised if one of them cannot be parsed. + Output in case of error can be customized with the ``msg`` argument. + .. method:: SimpleTestCase.assertXMLEqual(xml1, xml2, msg=None) .. versionadded:: 1.5 @@ -1644,6 +1631,8 @@ your test suite. syntax differences. When unvalid XML is passed in any parameter, an ``AssertionError`` is always raised, even if both string are identical. + Output in case of error can be customized with the ``msg`` argument. + .. method:: SimpleTestCase.assertXMLNotEqual(xml1, xml2, msg=None) .. versionadded:: 1.5 @@ -1652,6 +1641,68 @@ your test suite. comparison is based on XML semantics. See :meth:`~SimpleTestCase.assertXMLEqual` for details. + Output in case of error can be customized with the ``msg`` argument. + +.. method:: SimpleTestCase.assertInHTML(needle, haystack, count=None, msg_prefix='') + + .. versionadded:: 1.5 + + Asserts that the HTML fragment ``needle`` is contained in the ``haystack`` one. + + If the ``count`` integer argument is specified, then additionally the number + of ``needle`` occurrences will be strictly verified. + + Whitespace in most cases is ignored, and attribute ordering is not + significant. The passed-in arguments must be valid HTML. + +.. method:: SimpleTestCase.assertJSONEqual(raw, expected_data, msg=None) + + .. versionadded:: 1.5 + + Asserts that the JSON fragments ``raw`` and ``expected_data`` are equal. + Usual JSON non-significant whitespace rules apply as the heavyweight is + delegated to the :mod:`json` library. + + Output in case of error can be customized with the ``msg`` argument. + +.. method:: TransactionTestCase.assertQuerysetEqual(qs, values, transform=repr, ordered=True) + + Asserts that a queryset ``qs`` returns a particular list of values ``values``. + + The comparison of the contents of ``qs`` and ``values`` is performed using + the function ``transform``; by default, this means that the ``repr()`` of + each value is compared. Any other callable can be used if ``repr()`` doesn't + provide a unique or helpful comparison. + + By default, the comparison is also ordering dependent. If ``qs`` doesn't + provide an implicit ordering, you can set the ``ordered`` parameter to + ``False``, which turns the comparison into a Python set comparison. + + .. versionchanged:: 1.6 + + The method now checks for undefined order and raises ``ValueError`` + if undefined order is spotted. The ordering is seen as undefined if + the given ``qs`` isn't ordered and the comparison is against more + than one ordered values. + +.. method:: TransactionTestCase.assertNumQueries(num, func, *args, **kwargs) + + Asserts that when ``func`` is called with ``*args`` and ``**kwargs`` that + ``num`` database queries are executed. + + If a ``"using"`` key is present in ``kwargs`` it is used as the database + alias for which to check the number of queries. If you wish to call a + function with a ``using`` parameter you can do it by wrapping the call with + a ``lambda`` to add an extra parameter:: + + self.assertNumQueries(7, lambda: my_function(using=7)) + + You can also use this as a context manager:: + + with self.assertNumQueries(2): + Person.objects.create(name="Aaron") + Person.objects.create(name="Daniel") + .. _topics-testing-email: Email services @@ -1701,7 +1752,7 @@ and contents:: self.assertEqual(mail.outbox[0].subject, 'Subject here') As noted :ref:`previously <emptying-test-outbox>`, the test outbox is emptied -at the start of every test in a Django ``TestCase``. To empty the outbox +at the start of every test in a Django ``*TestCase``. To empty the outbox manually, assign the empty list to ``mail.outbox``:: from django.core import mail |
