Fixed #12364: Added graceful exit from a test run when Ctrl-C is pressed. Thanks Randy Barlow.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12034 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Karen Tracey 2009-12-31 18:48:28 +00:00
parent c35868ab9b
commit 9a55432213
4 changed files with 61 additions and 15 deletions

View File

@ -1,4 +1,7 @@
import sys
import signal
import unittest
from django.conf import settings
from django.db.models import get_app, get_apps
from django.test import _doctest as doctest
@ -11,22 +14,48 @@ 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
self._keyboard_interrupt_intercepted = False
def run(self, *args, **kwargs):
"""
Runs the test suite after registering a custom signal handler
that triggers a graceful exit when Ctrl-C is pressed.
"""
self._default_keyboard_interrupt_handler = signal.signal(signal.SIGINT,
self._keyboard_interrupt_handler)
result = super(DjangoTestRunner, self).run(*args, **kwargs)
signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)
return result
def _keyboard_interrupt_handler(self, signal_number, stack_frame):
"""
Handles Ctrl-C by setting a flag that will stop the test run when
the currently running test completes.
"""
self._keyboard_interrupt_intercepted = True
sys.stderr.write(" <Test run halted by Ctrl-C> ")
# Set the interrupt handler back to the default handler, so that
# another Ctrl-C press will trigger immediate exit.
signal.signal(signal.SIGINT, self._default_keyboard_interrupt_handler)
def _makeResult(self):
result = super(DjangoTestRunner, self)._makeResult()
failfast = self.failfast
def stoptest_override(func):
def stoptest(test):
if failfast and not result.wasSuccessful():
# If we were set to failfast and the unit test failed,
# or if the user has typed Ctrl-C, report and quit
if (failfast and not result.wasSuccessful()) or \
self._keyboard_interrupt_intercepted:
result.stop()
func(test)
return stoptest
setattr(result, 'stopTest', stoptest_override(result.stopTest))
return result

View File

@ -812,12 +812,10 @@ test <app or test identifier>
Runs tests for all installed models. See :ref:`topics-testing` for more
information.
--failfast
~~~~~~~~~~
.. versionadded:: 1.2
.. django-admin-option:: --failfast
Use the ``--failfast`` option to stop running tests and report the failure
Use the :djadminopt:`--failfast` option to stop running tests and report the failure
immediately after a test fails.
testserver <fixture fixture ...>

View File

@ -471,10 +471,12 @@ Models can now use a 64 bit :class:`~django.db.models.BigIntegerField` type.
Fast Failure for Tests
----------------------
The ``test`` subcommand of ``django-admin.py``, and the ``runtests.py`` script
used to run Django's own test suite, support a new ``--failfast`` option.
When specified, this option causes the test runner to exit after
encountering a failure instead of continuing with the test run.
The :djadmin:`test` subcommand of ``django-admin.py``, and the ``runtests.py``
script used to run Django's own test suite, support a new ``--failfast`` option.
When specified, this option causes the test runner to exit after encountering
a failure instead of continuing with the test run. In addition, the handling
of ``Ctrl-C`` during a test run has been improved to trigger a graceful exit
from the test run that reports details of the tests run before the interruption.
Improved localization
---------------------

View File

@ -242,8 +242,8 @@ in different circumstances.
Running tests
=============
Once you've written tests, run them using your project's ``manage.py``
utility::
Once you've written tests, run them using the :djadmin:`test` subcommand of
your project's ``manage.py`` utility::
$ ./manage.py test
@ -274,6 +274,23 @@ a test case, add the name of the test method to the label::
$ ./manage.py test animals.AnimalTestCase.testFluffyAnimals
.. versionadded:: 1.2
You can now trigger a graceful exit from a test run by pressing ``Ctrl-C``.
If you press ``Ctrl-C`` while the tests are running, the test runner will
wait fur the currently running test to complete and then exit gracefully.
During a graceful exit the test runner will output details of any test
failures, report on how many tests were run and how many errors and failures
were encountered, and destroy any test databases as usual. Thus pressing
``Ctrl-C`` can be very useful if you forget to pass the :djadminopt:`--failfast`
option, notice that some tests are unexpectedly failing, and want to get details
on the failures without waiting for the full test run to complete.
If you do not want to wait for the currently running test to finish, you
can press ``Ctrl-C`` a second time and the test run will halt immediately,
but not gracefully. No details of the tests run before the interruption will
be reported, and any test databases created by the run will not be destroyed.
The test database
-----------------