| 1 |
import unittest |
|---|
| 2 |
from django.conf import settings |
|---|
| 3 |
from django.db.models import get_app, get_apps |
|---|
| 4 |
from django.test import _doctest as doctest |
|---|
| 5 |
from django.test.utils import setup_test_environment, teardown_test_environment |
|---|
| 6 |
from django.test.testcases import OutputChecker, DocTestRunner |
|---|
| 7 |
|
|---|
| 8 |
# The module name for tests outside models.py |
|---|
| 9 |
TEST_MODULE = 'tests' |
|---|
| 10 |
|
|---|
| 11 |
doctestOutputChecker = OutputChecker() |
|---|
| 12 |
|
|---|
| 13 |
def get_tests(app_module): |
|---|
| 14 |
try: |
|---|
| 15 |
app_path = app_module.__name__.split('.')[:-1] |
|---|
| 16 |
test_module = __import__('.'.join(app_path + [TEST_MODULE]), {}, {}, TEST_MODULE) |
|---|
| 17 |
except ImportError, e: |
|---|
| 18 |
# Couldn't import tests.py. Was it due to a missing file, or |
|---|
| 19 |
# due to an import error in a tests.py that actually exists? |
|---|
| 20 |
import os.path |
|---|
| 21 |
from imp import find_module |
|---|
| 22 |
try: |
|---|
| 23 |
mod = find_module(TEST_MODULE, [os.path.dirname(app_module.__file__)]) |
|---|
| 24 |
except ImportError: |
|---|
| 25 |
# 'tests' module doesn't exist. Move on. |
|---|
| 26 |
test_module = None |
|---|
| 27 |
else: |
|---|
| 28 |
# The module exists, so there must be an import error in the |
|---|
| 29 |
# test module itself. We don't need the module; so if the |
|---|
| 30 |
# module was a single file module (i.e., tests.py), close the file |
|---|
| 31 |
# handle returned by find_module. Otherwise, the test module |
|---|
| 32 |
# is a directory, and there is nothing to close. |
|---|
| 33 |
if mod[0]: |
|---|
| 34 |
mod[0].close() |
|---|
| 35 |
raise |
|---|
| 36 |
return test_module |
|---|
| 37 |
|
|---|
| 38 |
def build_suite(app_module): |
|---|
| 39 |
"Create a complete Django test suite for the provided application module" |
|---|
| 40 |
suite = unittest.TestSuite() |
|---|
| 41 |
|
|---|
| 42 |
# Load unit and doctests in the models.py module. If module has |
|---|
| 43 |
# a suite() method, use it. Otherwise build the test suite ourselves. |
|---|
| 44 |
if hasattr(app_module, 'suite'): |
|---|
| 45 |
suite.addTest(app_module.suite()) |
|---|
| 46 |
else: |
|---|
| 47 |
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(app_module)) |
|---|
| 48 |
try: |
|---|
| 49 |
suite.addTest(doctest.DocTestSuite(app_module, |
|---|
| 50 |
checker=doctestOutputChecker, |
|---|
| 51 |
runner=DocTestRunner)) |
|---|
| 52 |
except ValueError: |
|---|
| 53 |
# No doc tests in models.py |
|---|
| 54 |
pass |
|---|
| 55 |
|
|---|
| 56 |
# Check to see if a separate 'tests' module exists parallel to the |
|---|
| 57 |
# models module |
|---|
| 58 |
test_module = get_tests(app_module) |
|---|
| 59 |
if test_module: |
|---|
| 60 |
# Load unit and doctests in the tests.py module. If module has |
|---|
| 61 |
# a suite() method, use it. Otherwise build the test suite ourselves. |
|---|
| 62 |
if hasattr(test_module, 'suite'): |
|---|
| 63 |
suite.addTest(test_module.suite()) |
|---|
| 64 |
else: |
|---|
| 65 |
suite.addTest(unittest.defaultTestLoader.loadTestsFromModule(test_module)) |
|---|
| 66 |
try: |
|---|
| 67 |
suite.addTest(doctest.DocTestSuite(test_module, |
|---|
| 68 |
checker=doctestOutputChecker, |
|---|
| 69 |
runner=DocTestRunner)) |
|---|
| 70 |
except ValueError: |
|---|
| 71 |
# No doc tests in tests.py |
|---|
| 72 |
pass |
|---|
| 73 |
return suite |
|---|
| 74 |
|
|---|
| 75 |
def build_test(label): |
|---|
| 76 |
"""Construct a test case a test with the specified label. Label should |
|---|
| 77 |
be of the form model.TestClass or model.TestClass.test_method. Returns |
|---|
| 78 |
an instantiated test or test suite corresponding to the label provided. |
|---|
| 79 |
|
|---|
| 80 |
""" |
|---|
| 81 |
parts = label.split('.') |
|---|
| 82 |
if len(parts) < 2 or len(parts) > 3: |
|---|
| 83 |
raise ValueError("Test label '%s' should be of the form app.TestCase or app.TestCase.test_method" % label) |
|---|
| 84 |
|
|---|
| 85 |
app_module = get_app(parts[0]) |
|---|
| 86 |
TestClass = getattr(app_module, parts[1], None) |
|---|
| 87 |
|
|---|
| 88 |
# Couldn't find the test class in models.py; look in tests.py |
|---|
| 89 |
if TestClass is None: |
|---|
| 90 |
test_module = get_tests(app_module) |
|---|
| 91 |
if test_module: |
|---|
| 92 |
TestClass = getattr(test_module, parts[1], None) |
|---|
| 93 |
|
|---|
| 94 |
if len(parts) == 2: # label is app.TestClass |
|---|
| 95 |
try: |
|---|
| 96 |
return unittest.TestLoader().loadTestsFromTestCase(TestClass) |
|---|
| 97 |
except TypeError: |
|---|
| 98 |
raise ValueError("Test label '%s' does not refer to a test class" % label) |
|---|
| 99 |
else: # label is app.TestClass.test_method |
|---|
| 100 |
return TestClass(parts[2]) |
|---|
| 101 |
|
|---|
| 102 |
def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]): |
|---|
| 103 |
""" |
|---|
| 104 |
Run the unit tests for all the test labels in the provided list. |
|---|
| 105 |
Labels must be of the form: |
|---|
| 106 |
- app.TestClass.test_method |
|---|
| 107 |
Run a single specific test method |
|---|
| 108 |
- app.TestClass |
|---|
| 109 |
Run all the test methods in a given class |
|---|
| 110 |
- app |
|---|
| 111 |
Search for doctests and unittests in the named application. |
|---|
| 112 |
|
|---|
| 113 |
When looking for tests, the test runner will look in the models and |
|---|
| 114 |
tests modules for the application. |
|---|
| 115 |
|
|---|
| 116 |
A list of 'extra' tests may also be provided; these tests |
|---|
| 117 |
will be added to the test suite. |
|---|
| 118 |
|
|---|
| 119 |
Returns the number of tests that failed. |
|---|
| 120 |
""" |
|---|
| 121 |
setup_test_environment() |
|---|
| 122 |
|
|---|
| 123 |
settings.DEBUG = False |
|---|
| 124 |
suite = unittest.TestSuite() |
|---|
| 125 |
|
|---|
| 126 |
if test_labels: |
|---|
| 127 |
for label in test_labels: |
|---|
| 128 |
if '.' in label: |
|---|
| 129 |
suite.addTest(build_test(label)) |
|---|
| 130 |
else: |
|---|
| 131 |
app = get_app(label) |
|---|
| 132 |
suite.addTest(build_suite(app)) |
|---|
| 133 |
else: |
|---|
| 134 |
for app in get_apps(): |
|---|
| 135 |
suite.addTest(build_suite(app)) |
|---|
| 136 |
|
|---|
| 137 |
for test in extra_tests: |
|---|
| 138 |
suite.addTest(test) |
|---|
| 139 |
|
|---|
| 140 |
old_name = settings.DATABASE_NAME |
|---|
| 141 |
from django.db import connection |
|---|
| 142 |
connection.creation.create_test_db(verbosity, autoclobber=not interactive) |
|---|
| 143 |
result = unittest.TextTestRunner(verbosity=verbosity).run(suite) |
|---|
| 144 |
connection.creation.destroy_test_db(old_name, verbosity) |
|---|
| 145 |
|
|---|
| 146 |
teardown_test_environment() |
|---|
| 147 |
|
|---|
| 148 |
return len(result.failures) + len(result.errors) |
|---|