diff --git a/django/contrib/formtools/tests.py b/django/contrib/formtools/tests.py
index 143857a..ba241e9 100644
--- a/django/contrib/formtools/tests.py
+++ b/django/contrib/formtools/tests.py
@@ -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.
diff --git a/django/core/urlresolvers.py b/django/core/urlresolvers.py
index 2ad63bf..ff0bcbc 100644
--- a/django/core/urlresolvers.py
+++ b/django/core/urlresolvers.py
@@ -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()
diff --git a/django/test/testcases.py b/django/test/testcases.py
index ee83b96..3bad399 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -4,10 +4,12 @@ from urlparse import urlsplit, urlunsplit
 
 from django.http import QueryDict
 from django.db import transaction
+from django.conf import settings
 from django.core import mail
 from django.core.management 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,6 +56,8 @@ class TestCase(unittest.TestCase):
             * 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)
@@ -61,6 +65,10 @@ class TestCase(unittest.TestCase):
             # 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 @@ class TestCase(unittest.TestCase):
             result.addError(self, sys.exc_info())
             return
         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):
diff --git a/docs/testing.txt b/docs/testing.txt
index befa697..67d2cfc 100644
--- a/docs/testing.txt
+++ b/docs/testing.txt
@@ -797,6 +797,26 @@ another test, or by the order of test execution.
 .. _dumpdata documentation: ../django-admin/#dumpdata-appname-appname
 .. _loaddata documentation: ../django-admin/#loaddata-fixture-fixture
 
+URLconf manipulation
+~~~~~~~~~~~~~~~~~~~~
+
+If your application provides an urls.py file, there's no guarantee that the
+project running the tests will have all your urls included, which is likely
+to make your tests fail.
+
+For that, ``TestCase`` accepts a member attribute called ``urls``, the python
+module referenced (as a string) in this attribute will be used as the
+``ROOT_URLCONF`` during the run of this specific ``TestCase``, example::
+
+    from django.test import TestCase
+    
+    class TestMyViews(TestCase):
+        urls = 'myapp.urls'
+
+        def testIndexPageView(self):
+            # Here you'd test your view using ``Client``.
+
+
 Emptying the test outbox
 ~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/tests/regressiontests/test_client_regress/models.py b/tests/regressiontests/test_client_regress/models.py
index a204ec3..48919e0 100644
--- a/tests/regressiontests/test_client_regress/models.py
+++ b/tests/regressiontests/test_client_regress/models.py
@@ -318,3 +318,18 @@ class ExceptionTests(TestCase):
             self.client.get("/test_client_regress/staff_only/")
         except SuspiciousOperation:
             self.fail("Staff should be able to visit this page")
+
+# We need two different tests to check the urlconf subsitution, one to check
+# it was changed, anotherone (without self.urls) to check it was reverted on
+# teardown. Hence, the second must always be run after the first one.
+class UrlconfSubstitutionTests(TestCase):
+    urls = 'regressiontests.test_client_regress.urls'
+
+    def test_urlconf_was_changed(self):
+        url = reverse('arg_view', args=['somename'])
+        self.assertEquals(url, '/arg_view/somename/')
+
+class zUrlconfSubstitutionTests(TestCase):
+    def test_urlconf_was_reverted(self):
+        url = reverse('arg_view', args=['somename'])
+        self.assertEquals(url, '/test_client_regress/arg_view/somename/')
