diff --git a/django/test/simple.py b/django/test/simple.py
|
a
|
b
|
|
| 1 | | import sys |
| 2 | | import signal |
| 3 | | |
| 4 | 1 | from django.conf import settings |
| 5 | 2 | from django.db.models import get_app, get_apps |
| 6 | 3 | from django.test import _doctest as doctest |
| … |
… |
|
| 26 | 23 | try: |
| 27 | 24 | app_path = app_module.__name__.split('.')[:-1] |
| 28 | 25 | test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE) |
| 29 | | except ImportError, e: |
| | 26 | except ImportError: |
| 30 | 27 | # Couldn't import tests.py. Was it due to a missing file, or |
| 31 | 28 | # due to an import error in a tests.py that actually exists? |
| 32 | 29 | import os.path |
| … |
… |
|
| 198 | 195 | def build_suite(self, test_labels, extra_tests=None, **kwargs): |
| 199 | 196 | suite = unittest.TestSuite() |
| 200 | 197 | |
| | 198 | exclude_labels = kwargs.get('exclude_labels') |
| | 199 | if exclude_labels is None: |
| | 200 | exclude_labels = [] |
| | 201 | |
| 201 | 202 | if test_labels: |
| 202 | 203 | for label in test_labels: |
| | 204 | if label in exclude_labels: |
| | 205 | if self.verbosity >= 1: |
| | 206 | if '.' in label: |
| | 207 | print 'Skipping %s test' % label |
| | 208 | else: |
| | 209 | print 'Skipping tests from app %s' % label |
| | 210 | continue |
| 203 | 211 | if '.' in label: |
| 204 | 212 | suite.addTest(build_test(label)) |
| 205 | 213 | else: |
| … |
… |
|
| 269 | 277 | A list of 'extra' tests may also be provided; these tests |
| 270 | 278 | will be added to the test suite. |
| 271 | 279 | |
| | 280 | It's also possible to specify a list of labels to exclude from the |
| | 281 | test suite by using the exclude_labels parameter. |
| | 282 | |
| 272 | 283 | Returns the number of tests that failed. |
| 273 | 284 | """ |
| | 285 | exclude_labels = kwargs.get('exclude_labels') |
| 274 | 286 | self.setup_test_environment() |
| 275 | | suite = self.build_suite(test_labels, extra_tests) |
| | 287 | suite = self.build_suite(test_labels, extra_tests, exclude_labels=exclude_labels) |
| 276 | 288 | old_config = self.setup_databases() |
| 277 | 289 | result = self.run_suite(suite) |
| 278 | 290 | self.teardown_databases(old_config) |
diff --git a/tests/runtests.py b/tests/runtests.py
|
a
|
b
|
|
| 1 | 1 | #!/usr/bin/env python |
| 2 | | import os, subprocess, sys, traceback |
| | 2 | import os |
| | 3 | import subprocess |
| | 4 | import sys |
| 3 | 5 | |
| 4 | 6 | import django.contrib as contrib |
| 5 | 7 | from django.utils import unittest |
| … |
… |
|
| 63 | 65 | |
| 64 | 66 | try: |
| 65 | 67 | module = load_app(self.model_label) |
| 66 | | except Exception, e: |
| | 68 | except Exception: |
| 67 | 69 | self.fail('Unable to load invalid model module') |
| 68 | 70 | |
| 69 | 71 | # Make sure sys.stdout is not a tty so that we get errors without |
| … |
… |
|
| 72 | 74 | orig_stdout = sys.stdout |
| 73 | 75 | s = StringIO() |
| 74 | 76 | sys.stdout = s |
| 75 | | count = get_validation_errors(s, module) |
| | 77 | get_validation_errors(s, module) |
| 76 | 78 | sys.stdout = orig_stdout |
| 77 | 79 | s.seek(0) |
| 78 | 80 | error_log = s.read() |
| … |
… |
|
| 85 | 87 | self.assert_(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected)) |
| 86 | 88 | self.assert_(not missing, "Missing Errors: " + '\n'.join(missing)) |
| 87 | 89 | |
| 88 | | def setup(verbosity, test_labels): |
| | 90 | def setup(verbosity, test_labels, exclude_labels): |
| 89 | 91 | from django.conf import settings |
| 90 | 92 | state = { |
| 91 | 93 | 'INSTALLED_APPS': settings.INSTALLED_APPS, |
| … |
… |
|
| 116 | 118 | # in our tests. |
| 117 | 119 | settings.MANAGERS = ("admin@djangoproject.com",) |
| 118 | 120 | |
| | 121 | if exclude_labels is None: |
| | 122 | exclude_labels = [] |
| | 123 | |
| 119 | 124 | # Load all the ALWAYS_INSTALLED_APPS. |
| 120 | 125 | # (This import statement is intentionally delayed until after we |
| 121 | 126 | # access settings because of the USE_I18N dependency.) |
| 122 | 127 | from django.db.models.loading import get_apps, load_app |
| 123 | 128 | get_apps() |
| 124 | 129 | |
| | 130 | # Only avoid loading an app if it is fully excluded, if testcases or test |
| | 131 | # methods names were excluded then load its apps normally |
| | 132 | exclude_apps = [label for label in exclude_labels if '.' not in label] |
| | 133 | |
| 125 | 134 | # Load all the test model apps. |
| 126 | | test_labels_set = set([label.split('.')[0] for label in test_labels]) |
| | 135 | test_labels_set = set([label.split('.')[0] for label in test_labels if label not in exclude_apps]) |
| 127 | 136 | for model_dir, model_name in get_test_models(): |
| 128 | 137 | model_label = '.'.join([model_dir, model_name]) |
| 129 | | # if the model was named on the command line, or |
| 130 | | # no models were named (i.e., run all), import |
| 131 | | # this model and add it to the list to test. |
| | 138 | # if the model was named on the command line, or no models were named |
| | 139 | # (i.e., run all), import this model and add it to the list to test. |
| | 140 | # Also, skip importing the test apps explicitly excluded by the user. |
| 132 | 141 | if not test_labels or model_name in test_labels_set: |
| | 142 | if model_name in exclude_apps: |
| | 143 | if verbosity >= 2: |
| | 144 | print "Skipping import of app %s" % model_name |
| | 145 | continue |
| 133 | 146 | if verbosity >= 2: |
| 134 | 147 | print "Importing model %s" % model_name |
| 135 | 148 | mod = load_app(model_label) |
| … |
… |
|
| 145 | 158 | for key, value in state.items(): |
| 146 | 159 | setattr(settings, key, value) |
| 147 | 160 | |
| 148 | | def django_tests(verbosity, interactive, failfast, test_labels): |
| | 161 | def django_tests(verbosity, interactive, failfast, test_labels, exclude_labels=None): |
| 149 | 162 | from django.conf import settings |
| 150 | | state = setup(verbosity, test_labels) |
| | 163 | state = setup(verbosity, test_labels, exclude_labels) |
| 151 | 164 | |
| 152 | 165 | # Add tests for invalid models. |
| 153 | 166 | extra_tests = [] |
| … |
… |
|
| 162 | 175 | except ValueError: |
| 163 | 176 | pass |
| 164 | 177 | |
| 165 | | # Run the test suite, including the extra validation tests. |
| | 178 | # Run the test suite, including the extra validation tests and skipping |
| | 179 | # the test explicitely excluded. |
| 166 | 180 | from django.test.utils import get_runner |
| 167 | 181 | if not hasattr(settings, 'TEST_RUNNER'): |
| 168 | 182 | settings.TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner' |
| … |
… |
|
| 180 | 194 | extra_tests=extra_tests) |
| 181 | 195 | else: |
| 182 | 196 | test_runner = TestRunner(verbosity=verbosity, interactive=interactive, failfast=failfast) |
| 183 | | failures = test_runner.run_tests(test_labels, extra_tests=extra_tests) |
| | 197 | failures = test_runner.run_tests(test_labels, extra_tests=extra_tests, exclude_labels=exclude_labels) |
| 184 | 198 | |
| 185 | 199 | teardown(state) |
| 186 | 200 | return failures |
| … |
… |
|
| 299 | 313 | help="Bisect the test suite to discover a test that causes a test failure when combined with the named test.") |
| 300 | 314 | parser.add_option('--pair', action='store', dest='pair', default=None, |
| 301 | 315 | help="Run the test suite in pairs with the named test to find problem pairs.") |
| | 316 | parser.add_option('-e', '--exclude', action='append', dest='exclude', default=None, |
| | 317 | help='Test to exclude (use multiple times to exclude multiple tests).') |
| 302 | 318 | options, args = parser.parse_args() |
| 303 | 319 | if options.settings: |
| 304 | 320 | os.environ['DJANGO_SETTINGS_MODULE'] = options.settings |
| … |
… |
|
| 311 | 327 | elif options.pair: |
| 312 | 328 | paired_tests(options.pair, options, args) |
| 313 | 329 | else: |
| 314 | | failures = django_tests(int(options.verbosity), options.interactive, options.failfast, args) |
| | 330 | failures = django_tests( |
| | 331 | int(options.verbosity), |
| | 332 | options.interactive, |
| | 333 | options.failfast, |
| | 334 | args, |
| | 335 | options.exclude |
| | 336 | ) |
| 315 | 337 | if failures: |
| 316 | 338 | sys.exit(bool(failures)) |