diff --git a/djblets/cache/tests.py b/djblets/cache/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b43cb1bb774075652878fb09af4b602a6d38988
--- /dev/null
+++ b/djblets/cache/tests.py
@@ -0,0 +1,55 @@
+from __future__ import unicode_literals
+
+from django.core.cache import cache
+
+from djblets.cache.backend import (cache_memoize, make_cache_key,
+                                   CACHE_CHUNK_SIZE)
+from djblets.testing.testcases import TestCase
+
+
+class CacheTests(TestCase):
+    def tearDown(self):
+        cache.clear()
+
+    def test_cache_memoize(self):
+        """Testing cache_memoize"""
+        cacheKey = "abc123"
+        testStr = "Test 123"
+
+        def cacheFunc(cacheCalled=[]):
+            self.assertTrue(not cacheCalled)
+            cacheCalled.append(True)
+            return testStr
+
+        result = cache_memoize(cacheKey, cacheFunc)
+        self.assertEqual(result, testStr)
+
+        # Call a second time. We should only call cacheFunc once.
+        result = cache_memoize(cacheKey, cacheFunc)
+        self.assertEqual(result, testStr)
+
+    def test_cache_memoize_large_files(self):
+        """Testing cache_memoize with large files"""
+        cacheKey = "abc123"
+
+        # This takes into account the size of the pickle data, and will
+        # get us to exactly 2 chunks of data in cache.
+        data = 'x' * (CACHE_CHUNK_SIZE * 2 - 8)
+
+        def cacheFunc(cacheCalled=[]):
+            self.assertTrue(not cacheCalled)
+            cacheCalled.append(True)
+            return data
+
+        result = cache_memoize(cacheKey, cacheFunc, large_data=True,
+                               compress_large_data=False)
+        self.assertEqual(result, data)
+
+        self.assertTrue(make_cache_key(cacheKey) in cache)
+        self.assertTrue(make_cache_key('%s-0' % cacheKey) in cache)
+        self.assertTrue(make_cache_key('%s-1' % cacheKey) in cache)
+        self.assertFalse(make_cache_key('%s-2' % cacheKey) in cache)
+
+        result = cache_memoize(cacheKey, cacheFunc, large_data=True,
+                               compress_large_data=False)
+        self.assertEqual(result, data)
diff --git a/djblets/db/tests.py b/djblets/db/tests/test_local_data_query_set.py
similarity index 100%
rename from djblets/db/tests.py
rename to djblets/db/tests/test_local_data_query_set.py
diff --git a/djblets/db/tests/__init__.py b/djblets/db/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/djblets/db/tests/test_json_field.py b/djblets/db/tests/test_json_field.py
new file mode 100644
index 0000000000000000000000000000000000000000..6223317d8b4b2b5b8d42f56527fe3cca46ca867b
--- /dev/null
+++ b/djblets/db/tests/test_json_field.py
@@ -0,0 +1,77 @@
+from __future__ import unicode_literals
+
+from django.core.exceptions import ValidationError
+from django.utils import six
+
+from djblets.db.fields import JSONField
+from djblets.testing.testcases import TestCase
+
+
+class JSONFieldTests(TestCase):
+    """Unit tests for JSONField."""
+
+    def setUp(self):
+        self.field = JSONField()
+
+    def test_dumps_with_json_dict(self):
+        """Testing JSONField with dumping a JSON dictionary"""
+        result = self.field.dumps({'a': 1})
+        self.assertTrue(isinstance(result, six.string_types))
+        self.assertEqual(result, '{"a": 1}')
+
+    def test_dumps_with_json_string(self):
+        """Testing JSONField with dumping a JSON string"""
+        result = self.field.dumps('{"a": 1, "b": 2}')
+        self.assertTrue(isinstance(result, six.string_types))
+        self.assertEqual(result, '{"a": 1, "b": 2}')
+
+    def test_loading_json_dict(self):
+        """Testing JSONField with loading a JSON dictionary"""
+        result = self.field.loads('{"a": 1, "b": 2}')
+        self.assertTrue(isinstance(result, dict))
+        self.assertTrue('a' in result)
+        self.assertTrue('b' in result)
+
+    def test_loading_json_broken_dict(self):
+        """Testing JSONField with loading a badly serialized JSON dictionary"""
+        result = self.field.loads('{u"a": 1, u"b": 2}')
+        self.assertTrue(isinstance(result, dict))
+        self.assertTrue('a' in result)
+        self.assertTrue('b' in result)
+
+    def test_loading_json_array(self):
+        """Testing JSONField with loading a JSON array"""
+        result = self.field.loads('[1, 2, 3]')
+        self.assertTrue(isinstance(result, list))
+        self.assertEqual(result, [1, 2, 3])
+
+    def test_loading_string(self):
+        """Testing JSONField with loading a stored string"""
+        result = self.field.loads('"foo"')
+        self.assertTrue(isinstance(result, dict))
+        self.assertEqual(result, {})
+
+    def test_loading_broken_string(self):
+        """Testing JSONField with loading a broken stored string"""
+        result = self.field.loads('u"foo"')
+        self.assertTrue(isinstance(result, dict))
+        self.assertEqual(result, {})
+
+    def test_loading_python_code(self):
+        """Testing JSONField with loading Python code"""
+        result = self.field.loads('locals()')
+        self.assertTrue(isinstance(result, dict))
+        self.assertEqual(result, {})
+
+    def test_validate_with_valid_json_string(self):
+        """Testing JSONField with validating a valid JSON string"""
+        self.field.run_validators('{"a": 1, "b": 2}')
+
+    def test_validate_with_invalid_json_string(self):
+        """Testing JSONField with validating an invalid JSON string"""
+        self.assertRaises(ValidationError,
+                          lambda: self.field.run_validators('foo'))
+
+    def test_validate_with_json_dict(self):
+        """Testing JSONField with validating a JSON dictionary"""
+        self.field.run_validators({'a': 1, 'b': 2})
diff --git a/djblets/urls/tests.py b/djblets/urls/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..e2150827984daece9686c613827d13bdc5a1f4a9
--- /dev/null
+++ b/djblets/urls/tests.py
@@ -0,0 +1,57 @@
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.conf.urls import include, patterns, url
+from django.core.urlresolvers import NoReverseMatch, reverse
+
+from djblets.testing.testcases import TestCase
+from djblets.urls.resolvers import DynamicURLResolver
+
+
+class URLResolverTests(TestCase):
+    def setUp(self):
+        self._old_root_urlconf = settings.ROOT_URLCONF
+
+    def tearDown(self):
+        settings.ROOT_URLCONF = self._old_root_urlconf
+
+    def test_dynamic_url_resolver(self):
+        """Testing DynamicURLResolver"""
+        self.dynamic_urls = DynamicURLResolver()
+
+        settings.ROOT_URLCONF = patterns(
+            '',
+
+            url(r'^root/', include(patterns('', self.dynamic_urls))),
+            url(r'^foo/', self._dummy_view, name='foo'),
+        )
+
+        new_patterns = patterns(
+            '',
+
+            url(r'^bar/$', self._dummy_view, name='bar'),
+            url(r'^baz/$', self._dummy_view, name='baz'),
+        )
+
+        # The new patterns shouldn't reverse, just the original "foo".
+        reverse('foo')
+        self.assertRaises(NoReverseMatch, reverse, 'bar')
+        self.assertRaises(NoReverseMatch, reverse, 'baz')
+
+        # Add the new patterns. Now reversing should work.
+        self.dynamic_urls.add_patterns(new_patterns)
+
+        reverse('foo')
+        reverse('bar')
+        reverse('baz')
+
+        # Get rid of the patterns again. We should be back in the original
+        # state.
+        self.dynamic_urls.remove_patterns(new_patterns)
+
+        reverse('foo')
+        self.assertRaises(NoReverseMatch, reverse, 'bar')
+        self.assertRaises(NoReverseMatch, reverse, 'baz')
+
+    def _dummy_view(self):
+        pass
diff --git a/djblets/util/tests.py b/djblets/util/tests.py
index b0954eccca529327959d03236e21f6a9065b4748..ca41415cfc3d9a2556829a738ecdeb2215a43b48 100644
--- a/djblets/util/tests.py
+++ b/djblets/util/tests.py
@@ -28,21 +28,11 @@ from __future__ import unicode_literals
 import datetime
 import unittest
 
-from django.conf import settings
-from django.conf.urls import include, patterns, url
-from django.core.cache import cache
-from django.core.exceptions import ValidationError
-from django.core.urlresolvers import NoReverseMatch, reverse
 from django.http import HttpRequest
 from django.template import Token, TOKEN_TEXT, TemplateSyntaxError
-from django.utils import six
 from django.utils.html import strip_spaces_between_tags
 
-from djblets.cache.backend import (cache_memoize, make_cache_key,
-                                  CACHE_CHUNK_SIZE)
-from djblets.db.fields import JSONField
 from djblets.testing.testcases import TestCase, TagTest
-from djblets.urls.resolvers import DynamicURLResolver
 from djblets.util.http import (get_http_accept_lists,
                                get_http_requested_mimetype,
                                is_mimetype_a)
@@ -54,54 +44,6 @@ def normalize_html(s):
     return strip_spaces_between_tags(s).strip()
 
 
-class CacheTest(TestCase):
-    def tearDown(self):
-        cache.clear()
-
-    def test_cache_memoize(self):
-        """Testing cache_memoize"""
-        cacheKey = "abc123"
-        testStr = "Test 123"
-
-        def cacheFunc(cacheCalled=[]):
-            self.assertTrue(not cacheCalled)
-            cacheCalled.append(True)
-            return testStr
-
-        result = cache_memoize(cacheKey, cacheFunc)
-        self.assertEqual(result, testStr)
-
-        # Call a second time. We should only call cacheFunc once.
-        result = cache_memoize(cacheKey, cacheFunc)
-        self.assertEqual(result, testStr)
-
-    def test_cache_memoize_large_files(self):
-        """Testing cache_memoize with large files"""
-        cacheKey = "abc123"
-
-        # This takes into account the size of the pickle data, and will
-        # get us to exactly 2 chunks of data in cache.
-        data = 'x' * (CACHE_CHUNK_SIZE * 2 - 8)
-
-        def cacheFunc(cacheCalled=[]):
-            self.assertTrue(not cacheCalled)
-            cacheCalled.append(True)
-            return data
-
-        result = cache_memoize(cacheKey, cacheFunc, large_data=True,
-                               compress_large_data=False)
-        self.assertEqual(result, data)
-
-        self.assertTrue(make_cache_key(cacheKey) in cache)
-        self.assertTrue(make_cache_key('%s-0' % cacheKey) in cache)
-        self.assertTrue(make_cache_key('%s-1' % cacheKey) in cache)
-        self.assertFalse(make_cache_key('%s-2' % cacheKey) in cache)
-
-        result = cache_memoize(cacheKey, cacheFunc, large_data=True,
-                               compress_large_data=False)
-        self.assertEqual(result, data)
-
-
 class BoxTest(TagTest):
     def testPlain(self):
         """Testing box tag"""
@@ -359,118 +301,3 @@ class QuoteTextFilterTest(unittest.TestCase):
         """Testing quote_text filter (level 2)"""
         self.assertEqual(djblets_email.quote_text('foo\nbar', 2),
                          "> > foo\n> > bar")
-
-
-class JSONFieldTests(unittest.TestCase):
-    """Unit tests for JSONField."""
-
-    def setUp(self):
-        self.field = JSONField()
-
-    def test_dumps_with_json_dict(self):
-        """Testing JSONField with dumping a JSON dictionary"""
-        result = self.field.dumps({'a': 1})
-        self.assertTrue(isinstance(result, six.string_types))
-        self.assertEqual(result, '{"a": 1}')
-
-    def test_dumps_with_json_string(self):
-        """Testing JSONField with dumping a JSON string"""
-        result = self.field.dumps('{"a": 1, "b": 2}')
-        self.assertTrue(isinstance(result, six.string_types))
-        self.assertEqual(result, '{"a": 1, "b": 2}')
-
-    def test_loading_json_dict(self):
-        """Testing JSONField with loading a JSON dictionary"""
-        result = self.field.loads('{"a": 1, "b": 2}')
-        self.assertTrue(isinstance(result, dict))
-        self.assertTrue('a' in result)
-        self.assertTrue('b' in result)
-
-    def test_loading_json_broken_dict(self):
-        """Testing JSONField with loading a badly serialized JSON dictionary"""
-        result = self.field.loads('{u"a": 1, u"b": 2}')
-        self.assertTrue(isinstance(result, dict))
-        self.assertTrue('a' in result)
-        self.assertTrue('b' in result)
-
-    def test_loading_json_array(self):
-        """Testing JSONField with loading a JSON array"""
-        result = self.field.loads('[1, 2, 3]')
-        self.assertTrue(isinstance(result, list))
-        self.assertEqual(result, [1, 2, 3])
-
-    def test_loading_string(self):
-        """Testing JSONField with loading a stored string"""
-        result = self.field.loads('"foo"')
-        self.assertTrue(isinstance(result, dict))
-        self.assertEqual(result, {})
-
-    def test_loading_broken_string(self):
-        """Testing JSONField with loading a broken stored string"""
-        result = self.field.loads('u"foo"')
-        self.assertTrue(isinstance(result, dict))
-        self.assertEqual(result, {})
-
-    def test_loading_python_code(self):
-        """Testing JSONField with loading Python code"""
-        result = self.field.loads('locals()')
-        self.assertTrue(isinstance(result, dict))
-        self.assertEqual(result, {})
-
-    def test_validate_with_valid_json_string(self):
-        """Testing JSONField with validating a valid JSON string"""
-        self.field.run_validators('{"a": 1, "b": 2}')
-
-    def test_validate_with_invalid_json_string(self):
-        """Testing JSONField with validating an invalid JSON string"""
-        self.assertRaises(ValidationError,
-                          lambda: self.field.run_validators('foo'))
-
-    def test_validate_with_json_dict(self):
-        """Testing JSONField with validating a JSON dictionary"""
-        self.field.run_validators({'a': 1, 'b': 2})
-
-
-class URLResolverTests(unittest.TestCase):
-    def setUp(self):
-        self._old_root_urlconf = settings.ROOT_URLCONF
-
-    def tearDown(self):
-        settings.ROOT_URLCONF = self._old_root_urlconf
-
-    def test_dynamic_url_resolver(self):
-        """Testing DynamicURLResolver"""
-        self.dynamic_urls = DynamicURLResolver()
-
-        settings.ROOT_URLCONF = patterns('',
-            url(r'^root/', include(patterns('', self.dynamic_urls))),
-            url(r'^foo/', self._dummy_view, name='foo'),
-        )
-
-        new_patterns = patterns('',
-            url(r'^bar/$', self._dummy_view, name='bar'),
-            url(r'^baz/$', self._dummy_view, name='baz'),
-        )
-
-        # The new patterns shouldn't reverse, just the original "foo".
-        reverse('foo')
-        self.assertRaises(NoReverseMatch, reverse, 'bar')
-        self.assertRaises(NoReverseMatch, reverse, 'baz')
-
-        # Add the new patterns. Now reversing should work.
-        self.dynamic_urls.add_patterns(new_patterns)
-
-        reverse('foo')
-        reverse('bar')
-        reverse('baz')
-
-        # Get rid of the patterns again. We should be back in the original
-        # state.
-        self.dynamic_urls.remove_patterns(new_patterns)
-
-        reverse('foo')
-        self.assertRaises(NoReverseMatch, reverse, 'bar')
-        self.assertRaises(NoReverseMatch, reverse, 'baz')
-
-    def _dummy_view(self):
-        pass
