mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
Fixed #12991 -- Added unittest2 support. Thanks to PaulM for the draft patch, and to Luke, Karen, Justin, Alex, Łukasz Rekucki, and Chuck Harmston for their help testing and reviewing the final patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@14139 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
@@ -3,5 +3,5 @@ Django Unit Test and Doctest framework.
|
||||
"""
|
||||
|
||||
from django.test.client import Client
|
||||
from django.test.testcases import TestCase, TransactionTestCase
|
||||
from django.test.testcases import TestCase, TransactionTestCase, skipIfDBFeature, skipUnlessDBFeature
|
||||
from django.test.utils import Approximate
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
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
|
||||
from django.test.utils import setup_test_environment, teardown_test_environment
|
||||
from django.test.testcases import OutputChecker, DocTestRunner, TestCase
|
||||
from django.utils import unittest
|
||||
|
||||
# The module name for tests outside models.py
|
||||
TEST_MODULE = 'tests'
|
||||
@@ -14,52 +14,13 @@ 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)
|
||||
try:
|
||||
result = super(DjangoTestRunner, self).run(*args, **kwargs)
|
||||
finally:
|
||||
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 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
|
||||
|
||||
result.stopTest = stoptest_override(result.stopTest)
|
||||
return result
|
||||
def __init__(self, *args, **kwargs):
|
||||
import warnings
|
||||
warnings.warn(
|
||||
"DjangoTestRunner is deprecated; it's functionality is indistinguishable from TextTestRunner",
|
||||
PendingDeprecationWarning
|
||||
)
|
||||
super(DjangoTestRunner, self).__init__(*args, **kwargs)
|
||||
|
||||
def get_tests(app_module):
|
||||
try:
|
||||
@@ -232,6 +193,7 @@ class DjangoTestSuiteRunner(object):
|
||||
def setup_test_environment(self, **kwargs):
|
||||
setup_test_environment()
|
||||
settings.DEBUG = False
|
||||
unittest.installHandler()
|
||||
|
||||
def build_suite(self, test_labels, extra_tests=None, **kwargs):
|
||||
suite = unittest.TestSuite()
|
||||
@@ -271,7 +233,7 @@ class DjangoTestSuiteRunner(object):
|
||||
return old_names, mirrors
|
||||
|
||||
def run_suite(self, suite, **kwargs):
|
||||
return DjangoTestRunner(verbosity=self.verbosity, failfast=self.failfast).run(suite)
|
||||
return unittest.TextTestRunner(verbosity=self.verbosity, failfast=self.failfast).run(suite)
|
||||
|
||||
def teardown_databases(self, old_config, **kwargs):
|
||||
from django.db import connections
|
||||
@@ -284,6 +246,7 @@ class DjangoTestSuiteRunner(object):
|
||||
connection.creation.destroy_test_db(old_name, self.verbosity)
|
||||
|
||||
def teardown_test_environment(self, **kwargs):
|
||||
unittest.removeHandler()
|
||||
teardown_test_environment()
|
||||
|
||||
def suite_result(self, suite, result, **kwargs):
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import re
|
||||
import unittest
|
||||
from urlparse import urlsplit, urlunsplit
|
||||
from xml.dom.minidom import parseString, Node
|
||||
|
||||
@@ -7,12 +6,14 @@ from django.conf import settings
|
||||
from django.core import mail
|
||||
from django.core.management import call_command
|
||||
from django.core.urlresolvers import clear_url_caches
|
||||
from django.db import transaction, connections, DEFAULT_DB_ALIAS
|
||||
from django.db import transaction, connection, connections, DEFAULT_DB_ALIAS
|
||||
from django.http import QueryDict
|
||||
from django.test import _doctest as doctest
|
||||
from django.test.client import Client
|
||||
from django.utils import simplejson
|
||||
from django.utils import simplejson, unittest
|
||||
from django.utils.encoding import smart_str
|
||||
from django.utils.functional import wraps
|
||||
|
||||
|
||||
try:
|
||||
all
|
||||
@@ -22,6 +23,7 @@ except NameError:
|
||||
normalize_long_ints = lambda s: re.sub(r'(?<![\w])(\d+)L(?![\w])', '\\1', s)
|
||||
normalize_decimals = lambda s: re.sub(r"Decimal\('(\d+(\.\d*)?)'\)", lambda m: "Decimal(\"%s\")" % m.groups()[0], s)
|
||||
|
||||
|
||||
def to_list(value):
|
||||
"""
|
||||
Puts value into a list if it's not already one.
|
||||
@@ -472,7 +474,7 @@ def connections_support_transactions():
|
||||
Returns True if all connections support transactions. This is messy
|
||||
because 2.4 doesn't support any or all.
|
||||
"""
|
||||
return all(conn.settings_dict['SUPPORTS_TRANSACTIONS']
|
||||
return all(conn.features.supports_transactions
|
||||
for conn in connections.all())
|
||||
|
||||
class TestCase(TransactionTestCase):
|
||||
@@ -528,3 +530,25 @@ class TestCase(TransactionTestCase):
|
||||
|
||||
for connection in connections.all():
|
||||
connection.close()
|
||||
|
||||
def _deferredSkip(condition, reason):
|
||||
def decorator(test_item):
|
||||
if not (isinstance(test_item, type) and issubclass(test_item, TestCase)):
|
||||
@wraps(test_item)
|
||||
def skip_wrapper(*args, **kwargs):
|
||||
if condition():
|
||||
raise unittest.SkipTest(reason)
|
||||
test_item = skip_wrapper
|
||||
test_item.__unittest_skip_why__ = reason
|
||||
return test_item
|
||||
return decorator
|
||||
|
||||
def skipIfDBFeature(feature):
|
||||
"Skip a test if a database has the named feature"
|
||||
return _deferredSkip(lambda: getattr(connection.features, feature),
|
||||
"Database has feature %s" % feature)
|
||||
|
||||
def skipUnlessDBFeature(feature):
|
||||
"Skip a test unless a database has the named feature"
|
||||
return _deferredSkip(lambda: not getattr(connection.features, feature),
|
||||
"Database doesn't support feature %s" % feature)
|
||||
|
||||
Reference in New Issue
Block a user