Browse files

Fixed #7521 -- Added the ability to customize ROOT_URLCONF for the d…

…uration of a TestCase. Thanks to Mark Fargas (telenieko) for his work on this patch.

git-svn-id: bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
freakboy3742 committed Jun 30, 2008
1 parent 61898d8 commit 415bd694f9de8252e8d47bdf3df73cc62ca97728
@@ -21,18 +21,14 @@ class TestForm(forms.Form):
class PreviewTests(TestCase):
+ urls = 'django.contrib.formtools.test_urls'
def setUp(self):
- self._old_root_urlconf = settings.ROOT_URLCONF
- settings.ROOT_URLCONF = 'django.contrib.formtools.test_urls'
# Create a FormPreview instance to share between tests
self.preview = preview.FormPreview(TestForm)
input_template = '<input type="hidden" name="%s" value="%s" />'
self.input = input_template % (self.preview.unused_name('stage'), "%d")
- def tearDown(self):
- settings.ROOT_URLCONF = self._old_root_urlconf
def test_unused_name(self):
Verifies name mangling to get uniue field name.
@@ -296,3 +296,8 @@ def reverse(viewname, urlconf=None, args=None, kwargs=None):
kwargs = kwargs or {}
return iri_to_uri(u'/' + get_resolver(urlconf).reverse(viewname, *args, **kwargs))
+def clear_url_caches():
+ global _resolver_cache
+ global _callable_cache
+ _resolver_cache.clear()
+ _callable_cache.clear()
@@ -4,10 +4,12 @@
from django.http import QueryDict
from django.db import transaction
+from django.conf import settings
from django.core import mail
from import call_command
from django.test import _doctest as doctest
from django.test.client import Client
+from django.core.urlresolvers import clear_url_caches
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
@@ -54,13 +56,19 @@ def _pre_setup(self):
* Flushing the database.
* If the Test Case class has a 'fixtures' member, installing the
named fixtures.
+ * If the Test Case class has a 'urls' member, replace the
+ ROOT_URLCONF with it.
* Clearing the mail test outbox.
call_command('flush', verbosity=0, interactive=False)
if hasattr(self, 'fixtures'):
# We have to use this slightly awkward syntax due to the fact
# that we're using *args and **kwargs together.
call_command('loaddata', *self.fixtures, **{'verbosity': 0})
+ if hasattr(self, 'urls'):
+ self._old_root_urlconf = settings.ROOT_URLCONF
+ settings.ROOT_URLCONF = self.urls
+ clear_url_caches()
mail.outbox = []
def __call__(self, result=None):
@@ -79,6 +87,23 @@ def __call__(self, result=None):
result.addError(self, sys.exc_info())
super(TestCase, self).__call__(result)
+ try:
+ self._post_teardown()
+ except (KeyboardInterrupt, SystemExit):
+ raise
+ except Exception:
+ import sys
+ result.addError(self, sys.exc_info())
+ return
+ def _post_teardown(self):
+ """ Performs any post-test things. This includes:
+ * Putting back the original ROOT_URLCONF if it was changed.
+ """
+ if hasattr(self, '_old_root_urlconf'):
+ settings.ROOT_URLCONF = self._old_root_urlconf
+ clear_url_caches()
def assertRedirects(self, response, expected_url, status_code=302,
target_status_code=200, host=None):
@@ -797,6 +797,37 @@ another test, or by the order of test execution.
.. _dumpdata documentation: ../django-admin/#dumpdata-appname-appname
.. _loaddata documentation: ../django-admin/#loaddata-fixture-fixture
+URLconf configuration
+**New in Django development version**
+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 views in your application at any URL of their choosing.
+This means that your 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
+configuration for the duration of the execution of a test suite.
+If your ``TestCase`` instance defines an ``urls`` attribute, the
+``TestCase`` will use the value of that attribute as the ``ROOT_URLCONF``
+for the duration of that test.
+For example::
+ from django.test import TestCase
+ class TestMyViews(TestCase):
+ urls = 'myapp.test_urls'
+ def testIndexPageView(self):
+ # Here you'd test your view using ``Client``.
+This test case will use the contents of ``myapp.test_urls`` as the
+URLconf for the duration of the test case.
Emptying the test outbox
@@ -318,3 +318,22 @@ def test_exception_cleared(self):
except SuspiciousOperation:"Staff should be able to visit this page")
+# We need two different tests to check URLconf subsitution - one to check
+# it was changed, and another one (without self.urls) to check it was reverted on
+# teardown. This pair of tests relies upon the alphabetical ordering of test execution.
+class UrlconfSubstitutionTests(TestCase):
+ urls = 'regressiontests.test_client_regress.urls'
+ def test_urlconf_was_changed(self):
+ "TestCase can enforce a custom URLConf on a per-test basis"
+ url = reverse('arg_view', args=['somename'])
+ self.assertEquals(url, '/arg_view/somename/')
+# This test needs to run *after* UrlconfSubstitutionTests; the zz prefix in the
+# name is to ensure alphabetical ordering.
+class zzUrlconfSubstitutionTests(TestCase):
+ def test_urlconf_was_reverted(self):
+ "URLconf is reverted to original value after modification in a TestCase"
+ url = reverse('arg_view', args=['somename'])
+ self.assertEquals(url, '/test_client_regress/arg_view/somename/')

0 comments on commit 415bd69

Please sign in to comment.