Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #12658 -- Fixed test discovery so ImportErrors aren't ignored w…

…hen both `tests` and `models` are packages. Thanks schinckel for the report and boxm for a patch for the issue.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16382 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit f0adae4c6e857cabdff790d20dff815a37645d6f 1 parent 0686b06
@ramiro ramiro authored
View
33 django/test/simple.py
@@ -1,4 +1,5 @@
import unittest as real_unittest
+
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_app, get_apps
@@ -6,6 +7,8 @@
from django.test.utils import setup_test_environment, teardown_test_environment
from django.test.testcases import OutputChecker, DocTestRunner, TestCase
from django.utils import unittest
+from django.utils.importlib import import_module
+from django.utils.module_loading import module_has_submodule
__all__ = ('DjangoTestRunner', 'DjangoTestSuiteRunner', 'run_tests')
@@ -24,27 +27,25 @@ def __init__(self, *args, **kwargs):
super(DjangoTestRunner, self).__init__(*args, **kwargs)
def get_tests(app_module):
+ parts = app_module.__name__.split('.')
+ prefix, last = parts[:-1], parts[-1]
try:
- app_path = app_module.__name__.split('.')[:-1]
- test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE)
- except ImportError, e:
+ test_module = import_module('.'.join(prefix + [TEST_MODULE]))
+ except ImportError:
# Couldn't import tests.py. Was it due to a missing file, or
# due to an import error in a tests.py that actually exists?
- import os.path
- from imp import find_module
- try:
- mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)])
- except ImportError:
- # 'tests' module doesn't exist. Move on.
+ # app_module either points to a models.py file, or models/__init__.py
+ # Tests are therefore either in same directory, or one level up
+ if last == 'models':
+ app_root = import_module('.'.join(prefix))
+ else:
+ app_root = app_module
+
+ if not module_has_submodule(app_root, TEST_MODULE):
test_module = None
else:
- # The module exists, so there must be an import error in the
- # test module itself. We don't need the module; so if the
- # module was a single file module (i.e., tests.py), close the file
- # handle returned by find_module. Otherwise, the test module
- # is a directory, and there is nothing to close.
- if mod[0]:
- mod[0].close()
+ # The module exists, so there must be an import error in the test
+ # module itself.
raise
return test_module
View
4 tests/regressiontests/test_runner/invalid_app/__init__.py
@@ -0,0 +1,4 @@
+# Example of app layout that causes issue #12658:
+# * Both `models` and `tests` are packages.
+# * The tests raise a ImportError exception.
+# `test_runner` tests performs test discovery on this app.
View
0  tests/regressiontests/test_runner/invalid_app/models/__init__.py
No changes.
View
4 tests/regressiontests/test_runner/invalid_app/tests/__init__.py
@@ -0,0 +1,4 @@
+# Tests that raise ImportError should not fail silently.
+# This is a support fixture for one test case in test_runner
+
+raise ImportError
View
20 tests/regressiontests/test_runner/tests.py
@@ -8,11 +8,18 @@
from django.core.exceptions import ImproperlyConfigured
from django.core.management import call_command
from django.test import simple
+from django.test.simple import get_tests
from django.test.utils import get_warnings_state, restore_warnings_state
from django.utils import unittest
+from django.utils.importlib import import_module
+
from regressiontests.admin_scripts.tests import AdminScriptTestCase
+TEST_APP_OK = 'regressiontests.test_runner.valid_app.models'
+TEST_APP_ERROR = 'regressiontests.test_runner.invalid_app.models'
+
+
class DjangoTestRunnerTests(unittest.TestCase):
def setUp(self):
self._warnings_state = get_warnings_state()
@@ -203,3 +210,16 @@ def test_all_options_given(self):
out, err = self.run_django_admin(args)
self.assertNoOutput(err)
self.assertOutput(out, 'bar:foo:31337')
+
+
+class ModulesTestsPackages(unittest.TestCase):
+ def test_get_tests(self):
+ "Check that the get_tests helper function can find tests in a directory"
+ module = import_module(TEST_APP_OK)
+ tests = get_tests(module)
+ self.assertIsInstance(tests, type(module))
+
+ def test_import_error(self):
+ "Test for #12658 - Tests with ImportError's shouldn't fail silently"
+ module = import_module(TEST_APP_ERROR)
+ self.assertRaises(ImportError, get_tests, module)
View
3  tests/regressiontests/test_runner/valid_app/__init__.py
@@ -0,0 +1,3 @@
+# Example of app layout to verify that the fix for #12658 doesn't break test
+# discovery when both `models` and `tests` are packages.
+# `test_runner` tests perform test discovery on this app.
View
0  tests/regressiontests/test_runner/valid_app/models/__init__.py
No changes.
View
0  tests/regressiontests/test_runner/valid_app/tests/__init__.py
No changes.
Please sign in to comment.
Something went wrong with that request. Please try again.