mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #11613: Added a failfast option for test running. Thanks jukvalim and Randy Barlow.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@11843 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
		| @@ -6,6 +6,8 @@ class Command(BaseCommand): | ||||
|     option_list = BaseCommand.option_list + ( | ||||
|         make_option('--noinput', action='store_false', dest='interactive', default=True, | ||||
|             help='Tells Django to NOT prompt the user for input of any kind.'), | ||||
|         make_option('--failfast', action='store_true', dest='failfast', default=False, | ||||
|             help='Tells Django to stop running the test suite after first failed test.') | ||||
|     ) | ||||
|     help = 'Runs the test suite for the specified applications, or the entire site if no apps are specified.' | ||||
|     args = '[appname ...]' | ||||
| @@ -15,11 +17,18 @@ class Command(BaseCommand): | ||||
|     def handle(self, *test_labels, **options): | ||||
|         from django.conf import settings | ||||
|         from django.test.utils import get_runner | ||||
|  | ||||
|          | ||||
|         verbosity = int(options.get('verbosity', 1)) | ||||
|         interactive = options.get('interactive', True) | ||||
|         failfast = options.get('failfast', False) | ||||
|         test_runner = get_runner(settings) | ||||
|  | ||||
|         failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive) | ||||
|         # Some custom test runners won't accept the failfast flag, so let's make sure they accept it before passing it to them | ||||
|         if 'failfast' in test_runner.func_code.co_varnames: | ||||
|             failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive,  | ||||
|                                    failfast=failfast) | ||||
|         else: | ||||
|             failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive) | ||||
|  | ||||
|         if failures: | ||||
|             sys.exit(failures) | ||||
|   | ||||
| @@ -10,6 +10,26 @@ TEST_MODULE = 'tests' | ||||
|  | ||||
| doctestOutputChecker = OutputChecker() | ||||
|  | ||||
| class DjangoTestRunner(unittest.TextTestRunner): | ||||
|      | ||||
|     def __init__(self, verbosity=0, failfast=False, **kwargs): | ||||
|         super(DjangoTestRunner, self).__init__(verbosity=verbosity, **kwargs) | ||||
|         self.failfast = failfast | ||||
|          | ||||
|     def _makeResult(self): | ||||
|         result = super(DjangoTestRunner, self)._makeResult() | ||||
|         failfast = self.failfast | ||||
|          | ||||
|         def stoptest_override(func): | ||||
|             def stoptest(test): | ||||
|                 if failfast and not result.wasSuccessful(): | ||||
|                     result.stop() | ||||
|                 func(test) | ||||
|             return stoptest | ||||
|          | ||||
|         setattr(result, 'stopTest', stoptest_override(result.stopTest)) | ||||
|         return result | ||||
|  | ||||
| def get_tests(app_module): | ||||
|     try: | ||||
|         app_path = app_module.__name__.split('.')[:-1] | ||||
| @@ -146,7 +166,7 @@ def reorder_suite(suite, classes): | ||||
|         bins[0].addTests(bins[i+1]) | ||||
|     return bins[0] | ||||
|  | ||||
| def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]): | ||||
| def run_tests(test_labels, verbosity=1, interactive=True, failfast=False, extra_tests=[]): | ||||
|     """ | ||||
|     Run the unit tests for all the test labels in the provided list. | ||||
|     Labels must be of the form: | ||||
| @@ -189,7 +209,7 @@ def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]): | ||||
|     old_name = settings.DATABASE_NAME | ||||
|     from django.db import connection | ||||
|     connection.creation.create_test_db(verbosity, autoclobber=not interactive) | ||||
|     result = unittest.TextTestRunner(verbosity=verbosity).run(suite) | ||||
|     result = DjangoTestRunner(verbosity=verbosity, failfast=failfast).run(suite) | ||||
|     connection.creation.destroy_test_db(old_name, verbosity) | ||||
|  | ||||
|     teardown_test_environment() | ||||
|   | ||||
| @@ -696,6 +696,12 @@ test <app or test identifier> | ||||
| Runs tests for all installed models. See :ref:`topics-testing` for more | ||||
| information. | ||||
|  | ||||
| --failfast | ||||
| ~~~~~~~~ | ||||
|  | ||||
| Use the ``--failfast`` option to stop running tests and report the failure  | ||||
| immediately after a test fails. | ||||
|  | ||||
| testserver <fixture fixture ...> | ||||
| -------------------------------- | ||||
|  | ||||
|   | ||||
| @@ -86,7 +86,7 @@ class InvalidModelTestCase(unittest.TestCase): | ||||
|         self.assert_(not unexpected, "Unexpected Errors: " + '\n'.join(unexpected)) | ||||
|         self.assert_(not missing, "Missing Errors: " + '\n'.join(missing)) | ||||
|  | ||||
| def django_tests(verbosity, interactive, test_labels): | ||||
| def django_tests(verbosity, interactive, failfast, test_labels): | ||||
|     from django.conf import settings | ||||
|  | ||||
|     old_installed_apps = settings.INSTALLED_APPS | ||||
| @@ -160,7 +160,8 @@ def django_tests(verbosity, interactive, test_labels): | ||||
|         settings.TEST_RUNNER = 'django.test.simple.run_tests' | ||||
|     test_runner = get_runner(settings) | ||||
|  | ||||
|     failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive, extra_tests=extra_tests) | ||||
|     failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive, failfast=failfast, | ||||
|                            extra_tests=extra_tests) | ||||
|     if failures: | ||||
|         sys.exit(failures) | ||||
|  | ||||
| @@ -182,6 +183,8 @@ if __name__ == "__main__": | ||||
|         help='Verbosity level; 0=minimal output, 1=normal output, 2=all output') | ||||
|     parser.add_option('--noinput', action='store_false', dest='interactive', default=True, | ||||
|         help='Tells Django to NOT prompt the user for input of any kind.') | ||||
|     parser.add_option('--failfast', action='store_true', dest='failfast', default=False, | ||||
|         help='Tells Django to stop running the test suite after first failed test.') | ||||
|     parser.add_option('--settings', | ||||
|         help='Python path to settings module, e.g. "myproject.settings". If this isn\'t provided, the DJANGO_SETTINGS_MODULE environment variable will be used.') | ||||
|     options, args = parser.parse_args() | ||||
| @@ -190,4 +193,4 @@ if __name__ == "__main__": | ||||
|     elif "DJANGO_SETTINGS_MODULE" not in os.environ: | ||||
|         parser.error("DJANGO_SETTINGS_MODULE is not set in the environment. " | ||||
|                       "Set it or use --settings.") | ||||
|     django_tests(int(options.verbosity), options.interactive, args) | ||||
|     django_tests(int(options.verbosity), options.interactive, options.failfast, args) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user