diff --git a/django/core/cache/backends/dummy.py b/django/core/cache/backends/dummy.py
index af8b62c..ca09547 100644
--- a/django/core/cache/backends/dummy.py
+++ b/django/core/cache/backends/dummy.py
@@ -32,7 +32,7 @@ class DummyCache(BaseCache):
         self.validate_key(key)
         return False
 
-    def set_many(self, data, version=None):
+    def set_many(self, data, timeout=None, version=None):
         pass
 
     def delete_many(self, keys, version=None):
diff --git a/django/test/testcases.py b/django/test/testcases.py
index 02717ff..634fb09 100644
--- a/django/test/testcases.py
+++ b/django/test/testcases.py
@@ -16,7 +16,7 @@ from django.db import (transaction, connection, connections, DEFAULT_DB_ALIAS,
 from django.http import QueryDict
 from django.test import _doctest as doctest
 from django.test.client import Client
-from django.test.utils import get_warnings_state, restore_warnings_state, override_settings
+from django.test.utils import get_warnings_state, restore_warnings_state, override_settings, _caches_used_during_test
 from django.utils import simplejson, unittest as ut2
 from django.utils.encoding import smart_str
 
@@ -251,6 +251,7 @@ class TransactionTestCase(ut2.TestCase):
               ROOT_URLCONF with it.
             * Clearing the mail test outbox.
         """
+        self._cache_setup()
         self._fixture_setup()
         self._urlconf_setup()
         mail.outbox = []
@@ -276,6 +277,13 @@ class TransactionTestCase(ut2.TestCase):
             settings.ROOT_URLCONF = self.urls
             clear_url_caches()
 
+    def _cache_setup(self):
+        """
+        Resets the list of caches used in preparation for test
+        """
+        global _caches_used_during_test
+        _caches_used_during_test.clear()
+
     def __call__(self, result=None):
         """
         Wrapper around default __call__ method to perform common Django test
@@ -315,6 +323,7 @@ class TransactionTestCase(ut2.TestCase):
         """
         self._fixture_teardown()
         self._urlconf_teardown()
+        self._cache_teardown()
         # Some DB cursors include SQL statements as part of cursor
         # creation. If you have a test that does rollback, the effect
         # of these statements is lost, which can effect the operation
@@ -332,6 +341,13 @@ class TransactionTestCase(ut2.TestCase):
         if hasattr(self, '_old_root_urlconf'):
             settings.ROOT_URLCONF = self._old_root_urlconf
             clear_url_caches()
+    
+    def _cache_teardown(self):
+        """
+        Clears values set in cache during test
+        """
+        for cache in _caches_used_during_test:
+            cache.delete_many(list(cache._keys_set_during_test))
 
     def save_warnings_state(self):
         """
diff --git a/django/test/utils.py b/django/test/utils.py
index 19a3190..47ce559 100644
--- a/django/test/utils.py
+++ b/django/test/utils.py
@@ -2,10 +2,11 @@ from __future__ import with_statement
 
 import sys
 import time
+import types
 import os
 import warnings
 from django.conf import settings, UserSettingsHolder
-from django.core import mail
+from django.core import mail, cache
 from django.core.mail.backends import locmem
 from django.test.signals import template_rendered, setting_changed
 from django.template import Template, loader, TemplateDoesNotExist
@@ -66,6 +67,63 @@ def instrumented_test_render(self, context):
     return self.nodelist.render(context)
 
 
+_caches_used_during_test = set()
+
+def modified_get_cache(backend, **kwargs):
+    """
+    Modifies the original get_cache so that we can track any keys set during a cache run and reset
+    them at the end.
+    """
+    requested_cache = cache.original_get_cache(backend, **kwargs)
+    
+    # Add '_test_' to key_prefix to ensure pre-existing cache values don't get touched
+    requested_cache.original_key_prefix = requested_cache.key_prefix
+    requested_cache.key_prefix = '_test_%s' % requested_cache.original_key_prefix
+    
+    # Keep track of which caches we use during a test
+    global _caches_used_during_test
+    _caches_used_during_test.add(requested_cache)
+    
+    requested_cache._keys_set_during_test = set()
+    
+    # Modify cache.set() to collect keys in _keys_set_during_test
+    requested_cache.original_set = requested_cache.set
+    def modified_set(self, key, value, timeout=None, version=None):
+        requested_cache._keys_set_during_test.add(key)
+        requested_cache.original_set(key, value, timeout, version)
+    requested_cache.set = types.MethodType(modified_set, requested_cache)
+    
+    # Modify cache.add() to collect keys in _keys_set_during_test
+    requested_cache.original_add = requested_cache.add
+    def modified_add(self, key, value, timeout=None, version=None):
+        requested_cache._keys_set_during_test.add(key)
+        return requested_cache.original_add(key, value, timeout, version)
+    requested_cache.add = types.MethodType(modified_add, requested_cache)
+    
+    # Modify cache.incr() to collect keys in _keys_set_during_test
+    requested_cache.original_incr = requested_cache.incr
+    def modified_incr(self, key, delta=1, version=None):
+        requested_cache._keys_set_during_test.add(key)
+        return requested_cache.original_incr(key, delta, version)
+    requested_cache.incr = types.MethodType(modified_incr, requested_cache)
+    
+    # Modify cache.decr() to collect keys in _keys_set_during_test
+    requested_cache.original_decr = requested_cache.decr
+    def modified_decr(self, key, delta=1, version=None):
+        requested_cache._keys_set_during_test.add(key)
+        return requested_cache.original_decr(key, delta, version)
+    requested_cache.decr = types.MethodType(modified_decr, requested_cache)
+    
+    # Modify cache.set_many() to collect keys in _keys_set_during_test
+    requested_cache.original_set_many = requested_cache.set_many
+    def modified_set_many(self, data, timeout=None, version=None):
+        requested_cache._keys_set_during_test.update(data.keys())
+        requested_cache.original_set_many(data, timeout, version)
+    requested_cache.set_many = types.MethodType(modified_set_many, requested_cache)
+    
+    return requested_cache
+
+
 def setup_test_environment():
     """Perform any global pre-test setup. This involves:
 
@@ -78,8 +136,14 @@ def setup_test_environment():
 
     mail.original_email_backend = settings.EMAIL_BACKEND
     settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
-
     mail.outbox = []
+    
+    cache.original_get_cache = cache.get_cache
+    cache.get_cache = modified_get_cache
+    
+    # Make sure django.core.cache.cache also uses the modified cache
+    cache.original_cache = cache.cache
+    cache.cache = cache.get_cache(cache.DEFAULT_CACHE_ALIAS)
 
     deactivate()
 
@@ -96,8 +160,12 @@ def teardown_test_environment():
 
     settings.EMAIL_BACKEND = mail.original_email_backend
     del mail.original_email_backend
-
     del mail.outbox
+    
+    cache.cache = cache.original_cache
+    del cache.original_cache
+    cache.get_cache = cache.original_get_cache
+    del cache.original_get_cache
 
 
 def get_warnings_state():
diff --git a/tests/regressiontests/test_utils/tests.py b/tests/regressiontests/test_utils/tests.py
index 673295b..6734cad 100644
--- a/tests/regressiontests/test_utils/tests.py
+++ b/tests/regressiontests/test_utils/tests.py
@@ -1,9 +1,13 @@
 from __future__ import with_statement
 
 import sys
+import tempfile
 
 from django.test import TestCase, skipUnlessDBFeature, skipIfDBFeature
-from django.utils.unittest import skip
+from django.utils.unittest import skip, skipUnless
+from django.conf import settings
+from django.core import management
+from django.core.cache import get_cache, DEFAULT_CACHE_ALIAS
 
 from models import Person
 
@@ -131,6 +135,180 @@ class SkippingExtraTests(TestCase):
         pass
 
 
+# We must set this via a function to confirm that cache set test has run
+# before cache get test
+_cache_set_test_has_run = False
+
+def cache_set_test_run():
+    global _cache_set_test_has_run
+    _cache_set_test_has_run = True
+
+def cache_get_test_finished():
+    global _cache_set_test_has_run
+    _cache_set_test_has_run = False
+
+
+class BaseCacheReset(TestCase):
+    @classmethod
+    def setUpClass(cls):
+        # Setup everything here, because setupClass is guaranteed to run first
+        cache = cls.original_cache()
+
+        # Add a "pre-existing" value to cache to ensure it gets reset properly
+        cache.set('salt', 'pepper') # We won't touch this one
+        cache.set('sweet', 'sour') # We will touch a key with this name and check if it's restored at the end
+        
+        # Sanity checks
+        assert cache.get('salt') == 'pepper'
+        assert cache.get('sweet') == 'sour'
+
+        # We manually prefix the test_ here because we are not trying to pretend these are part
+        # of the original cache. We're just making sure the values exist so that we can call incr/decr
+        # without using cache.set() first
+        cache.orig_key_prefix = cache.key_prefix
+        cache.key_prefix = '_test_%s' % cache.orig_key_prefix
+        try:
+            cache.set('going_up', 1)
+            cache.set('going_down', 2)
+        finally:
+            cache.key_prefix = cache.orig_key_prefix
+
+    def setUp(self):
+        # Set up cache again at the instance level. This one will get reset
+        self.cache = self.modified_cache()
+
+
+class CacheResetTestsMixin(object):
+    # Note test names start with a/b. This ensures test order is correct (which we're normally
+    # not supposed to worry about)
+    def test_a_set_cache_in_various_ways_in_one_test_method(self):
+        """
+        Set some cache stuff in this method, and then we'll sure it doesn't carry over to the next
+        """
+        sweet_result = self.cache.set('sweet', 'bitter')
+        left_result = self.cache.set('left', 'right')
+        loud_result = self.cache.add('loud', 'quiet')
+        
+        assert self.cache.get('going_up') == 1
+        going_up_result = self.cache.incr('going_up')
+        
+        assert self.cache.get('going_down') == 2
+        going_down_result = self.cache.decr('going_down')
+        
+        over_above_result = self.cache.set_many({'over': 'under', 'above': 'below'})
+
+        # Sanity checks
+        self.assertEqual(self.cache.get('sweet'), 'bitter')
+        self.assertEqual(sweet_result, None)
+        
+        self.assertEqual(self.cache.get('left'), 'right')
+        self.assertEqual(left_result, None)
+        
+        self.assertEqual(self.cache.get('loud'), 'quiet')
+        self.assertEqual(loud_result, True)
+        
+        self.assertEqual(self.cache.get('going_up'), 2)
+        self.assertEqual(going_up_result, 2)
+        
+        self.assertEqual(self.cache.get('going_down'), 1)
+        self.assertEqual(going_down_result, 1)
+        
+        self.assertEqual(self.cache.get('over'), 'under')
+        self.assertEqual(self.cache.get('above'), 'below')
+        self.assertEqual(over_above_result, None)
+
+        # Mark that set_cache tests have run
+        cache_set_test_run()
+
+    def test_b_get_cache_in_another_test_method(self):
+        # Confirm that set tests has already run
+        if not _cache_set_test_has_run:
+            self.skipTest("set_cache test did not run first!")
+
+        try:
+            self.assertEqual(self.cache.get('left'), None)
+            self.assertEqual(self.cache.get('loud'), None)
+            self.assertEqual(self.cache.get('going_up'), None)
+            self.assertEqual(self.cache.get('going_down'), None)
+            self.assertEqual(self.cache.get('over'), None)
+            self.assertEqual(self.cache.get('above'), None)
+
+            # Make sure pre-existing values are still correct
+            original_cache = self.__class__.original_cache()
+            self.assertEqual(original_cache.get('sweet'), 'sour')
+            self.assertEqual(original_cache.get('salt'), 'pepper')
+        finally:
+            # Mark get_cache tests finished
+            cache_get_test_finished()
+
+
+class LocMemCacheResetTests(BaseCacheReset, CacheResetTestsMixin):
+    backend_name = 'django.core.cache.backends.locmem.LocMemCache'
+
+    @classmethod
+    def original_cache(cls):
+        if not hasattr(cls, '_original_cache'):
+            from django.core.cache import original_get_cache
+            cls._original_cache = original_get_cache(cls.backend_name, LOCATION='test')
+        return cls._original_cache
+
+    def modified_cache(self):
+        return get_cache(self.backend_name, LOCATION='test')
+
+
+class FileBasedCacheResetTests(BaseCacheReset, CacheResetTestsMixin):
+    backend_name = 'django.core.cache.backends.filebased.FileBasedCache'
+
+    @classmethod
+    def original_cache(cls):
+        if not hasattr(cls, '_original_cache'):
+            cls.cache_dirname = tempfile.mkdtemp()
+            from django.core.cache import original_get_cache
+            cls._original_cache = original_get_cache(cls.backend_name, LOCATION=cls.cache_dirname)
+        return cls._original_cache
+
+    def modified_cache(self):
+        return get_cache(self.backend_name, LOCATION=self.cache_dirname)
+
+
+class DBCacheResetTests(BaseCacheReset, CacheResetTestsMixin):
+    backend_name = 'django.core.cache.backends.db.DatabaseCache'
+
+    @classmethod
+    def original_cache(cls):
+        if not hasattr(cls, '_original_cache'):
+            cls.cache_table_name = 'test_cache_table'
+            management.call_command('createcachetable', cls.cache_table_name, verbosity=0, interactive=False)
+            from django.core.cache import original_get_cache
+            cls._original_cache = original_get_cache(cls.backend_name, LOCATION=cls.cache_table_name)
+        return cls._original_cache
+
+    def modified_cache(self):
+        return get_cache(self.backend_name, LOCATION=self.cache_table_name)
+
+    @classmethod
+    def tearDownClass(cls):
+        from django.db import connection
+        cursor = connection.cursor()
+        cursor.execute('DROP TABLE %s' % connection.ops.quote_name(cls.cache_table_name))
+
+
+@skipUnless(settings.CACHES[DEFAULT_CACHE_ALIAS]['BACKEND'].startswith('django.core.cache.backends.memcached.'), "memcached not available")
+class MemcachedCacheResetTests(BaseCacheReset, CacheResetTestsMixin):
+    backend_name = 'django.core.cache.backends.memcached.MemcachedCache'
+
+    @classmethod
+    def original_cache(cls):
+        if not hasattr(cls, '_original_cache'):
+            cls.memcached_location = settings.CACHES[DEFAULT_CACHE_ALIAS]['LOCATION']
+            from django.core.cache import original_get_cache
+            cls._original_cache = original_get_cache(cls.backend_name, LOCATION=cls.memcached_location)
+        return cls._original_cache
+
+    def modified_cache(self):
+        return get_cache(self.backend_name, LOCATION=self.memcached_location)
+
+
 __test__ = {"API_TEST": r"""
 # Some checks of the doctest output normalizer.
 # Standard doctests do fairly
