root/trunk/test/simple.py

Revision 285, 5.1 kB (checked in by akaihola, 21 months ago)

[test] Fixed a typo in post-Django-1.0 compatibility code.

  • Property svn:eol-style set to native
Line 
1__doc__ = """
2In your settings, use
3
4  TEST_RUNNER = 'ambidjangolib.test.simple.run_tests_until_fail'
5
6to make `manage.py test` stop after the first test suite with failures, and
7only show the first failing test in the suite.
8"""
9
10
11from unittest import \
12     TestSuite, TextTestRunner, _TextTestResult, defaultTestLoader
13from django.test import _doctest as doctest
14from django.conf import settings
15from django.db import transaction, connection
16from django.db.models import get_app, get_apps
17from django.test.utils import \
18     setup_test_environment, teardown_test_environment
19from django.test.simple import build_test, get_tests, doctestOutputChecker
20from django.test.testcases import DocTestRunner
21
22try:
23    # pre-Django-1.0
24    from django.test.utils import create_test_db, destroy_test_db
25except ImportError:
26    # post-Django-1.0
27    def create_test_db(*args, **kwargs):
28        connection.creation.create_test_db(*args, **kwargs)
29    def destroy_test_db(*args, **kwargs):
30        connection.creation.destroy_test_db(*args, **kwargs)
31
32class DocTestRunner(doctest.DocTestRunner):
33    """
34    Replacement for django.test.testcases.DocTestRunner which unfortunately
35    overrides any supplied `optionflags=` kwarg with only `doctest.ELLIPSIS`.
36    We need to pass on optionflags.
37    """
38    def __init__(self, *args, **kwargs):
39        doctest.DocTestRunner.__init__(self, *args, **kwargs)
40        self.optionflags |= doctest.ELLIPSIS
41        # Django's original has `=` instead of `|=` here
42
43    def report_unexpected_exception(self, out, test, example, exc_info):
44        doctest.DocTestRunner.report_unexpected_exception(self, out, test,
45                                                          example, exc_info)
46        # Rollback, in case of database errors. Otherwise they'd have
47        # side effects on other tests.
48        transaction.rollback_unless_managed()
49
50
51def _add_tests_for_module(suite, module):
52    """
53    Repeated code from inside `build_suite()` is refactored here.
54    """
55    # Load unit and doctests in the given module. If module has a suite()
56    # method, use it. Otherwise build the test suite ourselves.
57    if hasattr(module, 'suite'):
58        suite.addTest(module.suite())
59    else:
60        suite.addTest(defaultTestLoader.loadTestsFromModule(module))
61        try:
62            suite.addTest(doctest.DocTestSuite(
63                module,
64                checker=doctestOutputChecker,
65                runner=DocTestRunner,
66                optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
67        except ValueError:
68            # No doc tests in models.py
69            pass
70
71
72def build_suite(app_module):
73    """
74    Create a complete Django test suite for the provided application module.
75
76    This overrides Django's original `django.test.simple.build_suite()` because
77    we need to pass the `REPORT_ONLY_FIRST_FAILURE` option flag to
78    `DocTestSuite` instances.
79    """
80    suite = TestSuite()
81
82    _add_tests_for_module(suite, app_module)
83
84    # Check to see if a separate 'tests' module exists parallel to the
85    # models module
86    test_module = get_tests(app_module)
87    if test_module:
88        _add_tests_for_module(suite, test_module)
89
90    return suite
91
92
93class _FailStopTextTestResult(_TextTestResult):
94    def addError(self, test, err):
95        _TextTestResult.addError(self, test, err)
96        self.shouldStop = True
97
98    def addFailure(self, test, err):
99        _TextTestResult.addFailure(self, test, err)
100        self.shouldStop = True
101
102
103class FailStopTextTestRunner(TextTestRunner):
104    def _makeResult(self):
105        return _FailStopTextTestResult(
106            self.stream, self.descriptions, self.verbosity)
107
108
109def run_tests_until_fail(test_labels, verbosity=1, interactive=True, extra_tests=[]):
110    """
111    Run the unit tests for all the test labels in the provided list.
112    Labels must be of the form:
113     - app.TestClass.test_method
114        Run a single specific test method
115     - app.TestClass
116        Run all the test methods in a given class
117     - app
118        Search for doctests and unittests in the named application.
119
120    When looking for tests, the test runner will look in the models and
121    tests modules for the application.
122
123    A list of 'extra' tests may also be provided; these tests
124    will be added to the test suite.
125
126    Stops the tests at the first failure and returns 1.  If all test pass,
127    returns 0.
128
129    Also displays only the first failure in the failing test suite.
130    """
131    setup_test_environment()
132
133    settings.DEBUG = False
134    suite = TestSuite()
135
136    if test_labels:
137        for label in test_labels:
138            if '.' in label:
139                suite.addTest(build_test(label))
140            else:
141                app = get_app(label)
142                suite.addTest(build_suite(app))
143    else:
144        for app in get_apps():
145            suite.addTest(build_suite(app))
146
147    for test in extra_tests:
148        suite.addTest(test)
149
150    old_name = settings.DATABASE_NAME
151    create_test_db(verbosity, autoclobber=not interactive)
152    result = FailStopTextTestRunner(verbosity=verbosity).run(suite)
153    destroy_test_db(old_name, verbosity)
154
155    teardown_test_environment()
156
157    return len(result.failures) + len(result.errors)
Note: See TracBrowser for help on using the browser.