Ticket #8363: 8363.exclude-tests.diff
File 8363.exclude-tests.diff, 19.3 KB (added by , 13 years ago) |
---|
-
django/core/management/commands/test.py
diff --git a/django/core/management/commands/test.py b/django/core/management/commands/test.py index 1b3f2be..17fdba0 100644
a b class Command(BaseCommand): 12 12 help='Tells Django to stop running the test suite after first failed test.'), 13 13 make_option('--testrunner', action='store', dest='testrunner', 14 14 help='Tells Django to use specified test runner class instead of the one '+ 15 'specified by the TEST_RUNNER setting.') 15 'specified by the TEST_RUNNER setting.'), 16 make_option('-e', '--exclude', dest='exclude_labels', action='append', default=[], 17 help='Test to exclude (use multiple --exclude to exclude multiple tests).'), 16 18 ) 17 19 help = 'Runs the test suite for the specified applications, or the entire site if no apps are specified.' 18 20 args = '[appname ...]' … … class Command(BaseCommand): 51 53 options.setdefault('failfast', False) 52 54 53 55 test_runner = TestRunner(**options) 54 failures = test_runner.run_tests(test_labels) 56 exclude_labels = options.get('exclude_labels') 57 failures = test_runner.run_tests(test_labels, 58 exclude_labels=exclude_labels) 55 59 56 60 if failures: 57 61 sys.exit(bool(failures)) -
django/test/simple.py
diff --git a/django/test/simple.py b/django/test/simple.py index c9adfd2..d345d2e 100644
a b from django.test import _doctest as doctest 7 7 from django.test.utils import setup_test_environment, teardown_test_environment 8 8 from django.test.testcases import OutputChecker, DocTestRunner, TestCase 9 9 from django.utils import unittest 10 from django.utils.datastructures import SortedDict 10 11 from django.utils.importlib import import_module 11 12 from django.utils.module_loading import module_has_submodule 12 13 … … def get_tests(app_module): 50 51 return test_module 51 52 52 53 def build_suite(app_module): 53 "Create a complete Django test suite for the provided application module" 54 """ 55 Create a complete Django test suite for the provided application module 56 """ 54 57 suite = unittest.TestSuite() 55 58 56 # Load unit and doctests in the models.py module. If module has57 # a suite() method, use it. Otherwise build the test suite ourselves.58 if hasattr(app_module, 'suite'):59 suite.addTest(app_module.suite())60 else:61 suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module))62 try:63 suite.addTest(doctest.DocTestSuite(app_module,64 checker=doctestOutputChecker,65 runner=DocTestRunner))66 except ValueError:67 # No doc tests in models.py68 pass69 70 # Check to see if a separate 'tests' module exists parallel to the71 # models module72 59 test_module = get_tests(app_module) 73 if test_module: 74 # Load unit and doctests in the tests.py module. If module has 75 # a suite() method, use it. Otherwise build the test suite ourselves. 76 if hasattr(test_module, 'suite'): 77 suite.addTest(test_module.suite()) 78 else: 79 suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module)) 80 try: 81 suite.addTest(doctest.DocTestSuite(test_module, 82 checker=doctestOutputChecker, 83 runner=DocTestRunner)) 84 except ValueError: 85 # No doc tests in tests.py 86 pass 60 61 for module in (app_module, test_module): 62 if module: 63 # Load unit and doctests in the module. If the module has a 64 # suite() method, use it. Otherwise build the test suite ourselves. 65 if hasattr(module, 'suite'): 66 suite.addTest(module.suite()) 67 else: 68 suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(module)) 69 try: 70 suite.addTest(doctest.DocTestSuite(module, 71 checker=doctestOutputChecker, 72 runner=DocTestRunner)) 73 except ValueError: 74 # No doc tests 75 pass 87 76 return suite 88 77 89 def build_test(label): 90 """Construct a test case with the specified label. Label should be of the 91 form model.TestClass or model.TestClass.test_method. Returns an 92 instantiated test or test suite corresponding to the label provided. 78 def get_test_cases(module, test_label, app_label, TestClass=None, test_name=None): 79 test_cases = SortedDict() 80 if TestClass is None: 81 for test_name in dir(module): 82 obj = getattr(module, test_name) 83 if isinstance(obj, type) and issubclass(obj, unittest.TestCase): 84 test_cases.update(get_test_cases(test_label, module, app_label, obj)) 85 else: 86 try: 87 if issubclass(TestClass, (unittest.TestCase, real_unittest.TestCase)): 88 if test_name: # label is app.TestClass.test_method 89 label = '%s.%s.%s' % (app_label, TestClass.__name__, test_name) 90 test_cases[label] = TestClass(test_name) 91 else: # label is app.TestClass 92 try: 93 for test_name in unittest.TestLoader().getTestCaseNames(TestClass): 94 label = '%s.%s.%s' % (app_label, TestClass.__name__, test_name) 95 test_cases[label] = TestClass(test_name) 96 except TypeError: 97 raise ValueError("Test label '%s' does not refer to a test class" % test_label) 98 except TypeError: 99 # TestClass isn't a TestClass - it must be a method or normal class 100 print "aa" 101 return test_cases 102 103 def get_doctests(module, test_label): 104 parts = test_label.split('.') 105 doctests = SortedDict() 106 try: 107 existing_doctests = doctest.DocTestSuite(module, 108 checker=doctestOutputChecker, 109 runner=DocTestRunner) 110 # Now iterate over the suite, looking for doctests whose name 111 # matches the pattern that was given 112 for test in existing_doctests: 113 if test._dt_test.name in ( 114 '%s.%s' % (module.__name__, '.'.join(parts[1:])), 115 '%s.__test__.%s' % (module.__name__, '.'.join(parts[1:]))): 116 doctests[test._dt_test.name] = test 117 except ValueError: 118 # No doctests found. 119 pass 120 return doctests 93 121 122 def get_test_dict(label): 123 """ 124 Returns a SortedDict with the associations label->test, where label is a 125 full string reference to a test (of the form app.TestClass.test_method) and 126 test is either a test case or a doctest. For example: 127 128 { 129 'auth.AnonymousUserBackendTest.test_get_all_permissions': 130 <django.contrib.auth.tests.auth_backends.AnonymousUserBackendTest testMethod=test_get_all_permissions>, 131 'auth.AnonymousUserBackendTest.test_has_module_perms': 132 <django.contrib.auth.tests.auth_backends.AnonymousUserBackendTest testMethod=test_has_module_perms>, 133 ... 134 } 94 135 """ 95 136 parts = label.split('.') 96 if len(parts) < 2 or len(parts) > 3:97 raise ValueError("Test label '%s' should be of the form app.TestCase or app.TestCase.test_method" % label)98 137 99 # 100 # First, look for TestCase instances with a name that matches 101 # 102 app_module = get_app(parts[0]) 103 test_module = get_tests(app_module) 104 TestClass = getattr(app_module, parts[1], None) 138 if len(parts) < 1 or len(parts) > 3: 139 raise ValueError("Test label '%s' should be of the form app, app.TestCase or app.TestCase.test_method" % label) 105 140 106 # Couldn't find the test class in models.py; look in tests.py107 if TestClass is None:108 if test_module:109 TestClass = getattr(test_module, parts[1], None)141 # First, parse the label to figure out the app, the TestCase and the test_method. 142 app_label = parts[0] 143 app_module = get_app(app_label) 144 test_module = get_tests(app_module) 110 145 111 try: 112 if issubclass(TestClass, (unittest.TestCase, real_unittest.TestCase)): 113 if len(parts) == 2: # label is app.TestClass 114 try: 115 return unittest.TestLoader().loadTestsFromTestCase(TestClass) 116 except TypeError: 117 raise ValueError("Test label '%s' does not refer to a test class" % label) 118 else: # label is app.TestClass.test_method 119 return TestClass(parts[2]) 120 except TypeError: 121 # TestClass isn't a TestClass - it must be a method or normal class 122 pass 146 if len(parts) == 1: 147 # Test label of the form: app 148 TestClass = None 149 test_name = None 150 else: 151 TestClass = getattr(app_module, parts[1], None) 152 # Couldn't find the test class in models.py; look in tests.py 153 if TestClass is None: 154 if test_module: 155 TestClass = getattr(test_module, parts[1], None) 156 157 if len(parts) == 2: 158 # Test label of the form: app.TestCase 159 test_name = None 160 else: 161 # Test label of the form: app.TestCase.test_method 162 test_name = parts[2] 163 164 # Then, generate the SortedDict of tests. 165 test_dict = SortedDict() 166 for module in (app_module, test_module): 167 if hasattr(module, 'suite'): 168 # If the module defines a suite() method then use it instead. 169 test_dict.update({ 170 '%s.%s' % (app_label, module.__name__): module.suite() 171 }) 172 # TODO: introspect the custom suite to unfold the whole test names. 173 else: 174 # Get the module's test cases 175 test_cases = get_test_cases(module, label, app_label, TestClass, test_name) 176 test_dict.update(test_cases) 177 # Get the module's doctests 178 doctests = get_doctests(module, label) 179 test_dict.update(doctests) 180 return test_dict 123 181 124 #125 # If there isn't a TestCase, look for a doctest that matches126 #127 tests = []128 for module in app_module, test_module:129 try:130 doctests = doctest.DocTestSuite(module,131 checker=doctestOutputChecker,132 runner=DocTestRunner)133 # Now iterate over the suite, looking for doctests whose name134 # matches the pattern that was given135 for test in doctests:136 if test._dt_test.name in (137 '%s.%s' % (module.__name__, '.'.join(parts[1:])),138 '%s.__test__.%s' % (module.__name__, '.'.join(parts[1:]))):139 tests.append(test)140 except ValueError:141 # No doctests found.142 pass143 144 # If no tests were found, then we were given a bad test label.145 if not tests:146 raise ValueError("Test label '%s' does not refer to a test" % label)147 148 # Construct a suite out of the tests that matched.149 return unittest.TestSuite(tests)150 182 151 183 def partition_suite(suite, classes, bins): 152 184 """ … … class DjangoTestSuiteRunner(object): 234 266 def build_suite(self, test_labels, extra_tests=None, **kwargs): 235 267 suite = unittest.TestSuite() 236 268 237 if test_labels: 238 for label in test_labels: 239 if '.' in label: 240 suite.addTest(build_test(label)) 241 else: 242 app = get_app(label) 243 suite.addTest(build_suite(app)) 244 else: 245 for app in get_apps(): 246 suite.addTest(build_suite(app)) 269 if not test_labels: 270 test_labels = [] 271 for app_label in settings.INSTALLED_APPS: 272 test_labels.append(app_label.split('.')[-1]) 273 274 test_dict = SortedDict() 275 for label in test_labels: 276 test_dict.update(get_test_dict(label)) 277 278 excluded_dict = SortedDict() 279 for label in kwargs.get('exclude_labels'): 280 excluded_dict.update(get_test_dict(label)) 281 282 for label, test in excluded_dict.iteritems(): 283 try: 284 # Remove from the dictionary of executable tests 285 del test_dict[label] 286 except KeyError: 287 # It's OK if we're trying to exclude a test label that isn't 288 # part of the original suite. Simply ignore. 289 pass 290 if self.verbosity >= 1: 291 print 'Excluding test: %s' % label 292 293 for label, test in test_dict.iteritems(): 294 suite.addTest(test) 247 295 248 296 if extra_tests: 249 297 for test in extra_tests: … … class DjangoTestSuiteRunner(object): 347 395 A list of 'extra' tests may also be provided; these tests 348 396 will be added to the test suite. 349 397 398 It's also possible to specify a list of labels to exclude from the 399 test suite by using the exclude_labels parameter. 400 350 401 Returns the number of tests that failed. 351 402 """ 403 exclude_labels = kwargs.get('exclude_labels') 352 404 self.setup_test_environment() 353 suite = self.build_suite(test_labels, extra_tests )405 suite = self.build_suite(test_labels, extra_tests, exclude_labels=exclude_labels) 354 406 old_config = self.setup_databases() 355 407 result = self.run_suite(suite) 356 408 self.teardown_databases(old_config) -
tests/runtests.py
diff --git a/tests/runtests.py b/tests/runtests.py index ba66d2a..264b1d7 100755
a b class InvalidModelTestCase(unittest.TestCase): 79 79 80 80 try: 81 81 module = load_app(self.module_label) 82 except Exception , e:82 except Exception: 83 83 self.fail('Unable to load invalid model module') 84 84 85 85 # Make sure sys.stdout is not a tty so that we get errors without … … class InvalidModelTestCase(unittest.TestCase): 88 88 orig_stdout = sys.stdout 89 89 s = StringIO() 90 90 sys.stdout = s 91 count =get_validation_errors(s, module)91 get_validation_errors(s, module) 92 92 sys.stdout = orig_stdout 93 93 s.seek(0) 94 94 error_log = s.read() … … class InvalidModelTestCase(unittest.TestCase): 101 101 self.assertTrue(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected)) 102 102 self.assertTrue(not missing, "Missing Errors: " + '\n'.join(missing)) 103 103 104 def setup(verbosity, test_labels ):104 def setup(verbosity, test_labels, exclude_labels): 105 105 from django.conf import settings 106 106 state = { 107 107 'INSTALLED_APPS': settings.INSTALLED_APPS, … … def setup(verbosity, test_labels): 136 136 # in our tests. 137 137 settings.MANAGERS = ("admin@djangoproject.com",) 138 138 139 if exclude_labels is None: 140 exclude_labels = [] 141 139 142 # Load all the ALWAYS_INSTALLED_APPS. 140 143 # (This import statement is intentionally delayed until after we 141 144 # access settings because of the USE_I18N dependency.) 142 145 from django.db.models.loading import get_apps, load_app 143 146 get_apps() 144 147 148 # Only avoid loading an app if it is fully excluded, if testscases or test 149 # methods names were excluded then load its apps normally. 150 exclude_apps = [label for label in exclude_labels if '.' not in label] 151 145 152 # Load all the test model apps. 146 test_labels_set = set([label.split('.')[0] for label in test_labels])147 153 test_modules = get_test_modules() 154 test_labels_set = set([label.split('.')[0] for label in test_labels if label not in exclude_apps]) 148 155 149 156 # If GeoDjango, then we'll want to add in the test applications 150 157 # that are a part of its test suite. … … def setup(verbosity, test_labels): 154 161 155 162 for module_dir, module_name in test_modules: 156 163 module_label = '.'.join([module_dir, module_name]) 157 # if the mod ule was named on the command line, or158 # no modules were named (i.e., run all), import159 # this module and add it to the list to test.164 # if the model was named on the command line, or no models were named 165 # (i.e., run all), import this model and add it to the list to test. 166 # Also, skip importing the test apps explicitly excluded by the user. 160 167 if not test_labels or module_name in test_labels_set: 168 if module_name in exclude_apps: 169 if verbosity >= 2: 170 print "Skipping import of app %s" % module_name 171 continue 161 172 if verbosity >= 2: 162 173 print "Importing application %s" % module_name 163 174 mod = load_app(module_label) … … def teardown(state): 175 186 for key, value in state.items(): 176 187 setattr(settings, key, value) 177 188 178 def django_tests(verbosity, interactive, failfast, test_labels ):189 def django_tests(verbosity, interactive, failfast, test_labels, exclude_labels=None): 179 190 from django.conf import settings 180 state = setup(verbosity, test_labels )191 state = setup(verbosity, test_labels, exclude_labels) 181 192 182 193 # Add tests for invalid models apps. 183 194 extra_tests = [] … … def django_tests(verbosity, interactive, failfast, test_labels): 198 209 from django.contrib.gis.tests import geodjango_suite 199 210 extra_tests.append(geodjango_suite(apps=False)) 200 211 201 # Run the test suite, including the extra validation tests. 212 # Run the test suite, including the extra validation tests and skipping 213 # the test explicitely excluded. 202 214 from django.test.utils import get_runner 203 215 if not hasattr(settings, 'TEST_RUNNER'): 204 216 settings.TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner' 205 217 TestRunner = get_runner(settings) 206 218 207 219 test_runner = TestRunner(verbosity=verbosity, interactive=interactive, failfast=failfast) 208 failures = test_runner.run_tests(test_labels, extra_tests=extra_tests )220 failures = test_runner.run_tests(test_labels, extra_tests=extra_tests, exclude_labels=exclude_labels) 209 221 210 222 teardown(state) 211 223 return failures … … if __name__ == "__main__": 324 336 help="Bisect the test suite to discover a test that causes a test failure when combined with the named test.") 325 337 parser.add_option('--pair', action='store', dest='pair', default=None, 326 338 help="Run the test suite in pairs with the named test to find problem pairs.") 339 parser.add_option('-e', '--exclude', action='append', dest='exclude', default=[], 340 help='Test to exclude (use multiple --exclude to exclude multiple tests).') 327 341 options, args = parser.parse_args() 328 342 if options.settings: 329 343 os.environ['DJANGO_SETTINGS_MODULE'] = options.settings … … if __name__ == "__main__": 338 352 elif options.pair: 339 353 paired_tests(options.pair, options, args) 340 354 else: 341 failures = django_tests(int(options.verbosity), options.interactive, options.failfast, args) 355 failures = django_tests( 356 int(options.verbosity), 357 options.interactive, 358 options.failfast, 359 args, 360 options.exclude 361 ) 342 362 if failures: 343 363 sys.exit(bool(failures))