diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2007-07-28 04:02:52 +0000 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2007-07-28 04:02:52 +0000 |
| commit | 650cea9170313d9a2197d4050f6dcabaaeaa3b20 (patch) | |
| tree | 971b87274c3a17d6e8df842ecf48a98d594602e1 /django | |
| parent | 5b8d2c9f0df1dbfadafeea6420fc5fc175e00376 (diff) | |
Fixed #4460 -- Added the ability to be more specific in the test cases that are executed. This is a backwards incompatible change for any user with a custom test runner. See the wiki for details.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5769 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django')
| -rw-r--r-- | django/core/management.py | 11 | ||||
| -rw-r--r-- | django/test/simple.py | 112 |
2 files changed, 83 insertions, 40 deletions
diff --git a/django/core/management.py b/django/core/management.py index 4862a7833f..edf11ce478 100644 --- a/django/core/management.py +++ b/django/core/management.py @@ -1331,16 +1331,11 @@ def runfcgi(args): runfastcgi(args) runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]' -def test(app_labels, verbosity=1, interactive=True): +def test(test_labels, verbosity=1, interactive=True): "Runs the test suite for the specified applications" from django.conf import settings from django.db.models import get_app, get_apps - - if len(app_labels) == 0: - app_list = get_apps() - else: - app_list = [get_app(app_label) for app_label in app_labels] - + test_path = settings.TEST_RUNNER.split('.') # Allow for Python 2.5 relative paths if len(test_path) > 1: @@ -1350,7 +1345,7 @@ def test(app_labels, verbosity=1, interactive=True): test_module = __import__(test_module_name, {}, {}, test_path[-1]) test_runner = getattr(test_module, test_path[-1]) - failures = test_runner(app_list, verbosity=verbosity, interactive=interactive) + failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive) if failures: sys.exit(failures) diff --git a/django/test/simple.py b/django/test/simple.py index 08e27429e4..6fa381ac4d 100644 --- a/django/test/simple.py +++ b/django/test/simple.py @@ -1,5 +1,6 @@ import unittest from django.conf import settings +from django.db.models import get_app, get_apps from django.test import _doctest as doctest from django.test.utils import setup_test_environment, teardown_test_environment from django.test.utils import create_test_db, destroy_test_db @@ -10,6 +11,31 @@ TEST_MODULE = 'tests' doctestOutputChecker = OutputChecker() +def get_tests(app_module): + try: + app_path = app_module.__name__.split('.')[:-1] + test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE) + except ImportError, e: + # 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. + 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() + raise + return test_module + def build_suite(app_module): "Create a complete Django test suite for the provided application module" suite = unittest.TestSuite() @@ -30,10 +56,8 @@ def build_suite(app_module): # Check to see if a separate 'tests' module exists parallel to the # models module - try: - app_path = app_module.__name__.split('.')[:-1] - test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE) - + test_module = get_tests(app_module) + if test_module: # Load unit and doctests in the tests.py module. If module has # a suite() method, use it. Otherwise build the test suite ourselves. if hasattr(test_module, 'suite'): @@ -47,34 +71,50 @@ def build_suite(app_module): except ValueError: # No doc tests in tests.py pass - except ImportError, e: - # 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. - pass - 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() - raise - return suite -def run_tests(module_list, verbosity=1, interactive=True, extra_tests=[]): +def build_test(label): + """Construct a test case a test with the specified label. Label should + be of the form model.TestClass or model.TestClass.test_method. Returns + an instantiated test or test suite corresponding to the label provided. + + """ + parts = label.split('.') + if len(parts) < 2 or len(parts) > 3: + raise ValueError("Test label '%s' should be of the form app.TestCase or app.TestCase.test_method" % label) + + app_module = get_app(parts[0]) + TestClass = getattr(app_module, parts[1], None) + + # Couldn't find the test class in models.py; look in tests.py + if TestClass is None: + test_module = get_tests(app_module) + if test_module: + TestClass = getattr(test_module, parts[1], None) + + if len(parts) == 2: # label is app.TestClass + try: + return unittest.TestLoader().loadTestsFromTestCase(TestClass) + except TypeError: + raise ValueError("Test label '%s' does not refer to a test class" % label) + else: # label is app.TestClass.test_method + return TestClass(parts[2]) + +def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]): """ - Run the unit tests for all the modules in the provided list. - This testrunner will search each of the modules in the provided list, - looking for doctests and unittests in models.py or tests.py within - the module. A list of 'extra' tests may also be provided; these tests + Run the unit tests for all the test labels in the provided list. + Labels must be of the form: + - app.TestClass.test_method + Run a single specific test method + - app.TestClass + Run all the test methods in a given class + - app + Search for doctests and unittests in the named application. + + When looking for tests, the test runner will look in the models and + tests modules for the application. + + A list of 'extra' tests may also be provided; these tests will be added to the test suite. Returns the number of tests that failed. @@ -83,9 +123,17 @@ def run_tests(module_list, verbosity=1, interactive=True, extra_tests=[]): settings.DEBUG = False suite = unittest.TestSuite() - - for module in module_list: - suite.addTest(build_suite(module)) + + if test_labels: + for label in test_labels: + if '.' in label: + suite.addTest(build_test(label)) + else: + app = get_app(label) + suite.addTest(build_suite(app)) + else: + for app in get_apps(): + suite.addTest(build_suite(app)) for test in extra_tests: suite.addTest(test) |
