web/lib/django/test/simple.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     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, TestCase
       
     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         if not TestClass:
       
   101             raise ValueError("Test label '%s' does not refer to a test class" % label)
       
   102         return TestClass(parts[2])
       
   103 
       
   104 # Python 2.3 compatibility: TestSuites were made iterable in 2.4.
       
   105 # We need to iterate over them, so we add the missing method when
       
   106 # necessary.
       
   107 try:
       
   108     getattr(unittest.TestSuite, '__iter__')
       
   109 except AttributeError:
       
   110     setattr(unittest.TestSuite, '__iter__', lambda s: iter(s._tests))
       
   111 
       
   112 def partition_suite(suite, classes, bins):
       
   113     """
       
   114     Partitions a test suite by test type.
       
   115 
       
   116     classes is a sequence of types
       
   117     bins is a sequence of TestSuites, one more than classes
       
   118 
       
   119     Tests of type classes[i] are added to bins[i],
       
   120     tests with no match found in classes are place in bins[-1]
       
   121     """
       
   122     for test in suite:
       
   123         if isinstance(test, unittest.TestSuite):
       
   124             partition_suite(test, classes, bins)
       
   125         else:
       
   126             for i in range(len(classes)):
       
   127                 if isinstance(test, classes[i]):
       
   128                     bins[i].addTest(test)
       
   129                     break
       
   130             else:
       
   131                 bins[-1].addTest(test)
       
   132 
       
   133 def reorder_suite(suite, classes):
       
   134     """
       
   135     Reorders a test suite by test type.
       
   136 
       
   137     classes is a sequence of types
       
   138 
       
   139     All tests of type clases[0] are placed first, then tests of type classes[1], etc.
       
   140     Tests with no match in classes are placed last.
       
   141     """
       
   142     class_count = len(classes)
       
   143     bins = [unittest.TestSuite() for i in range(class_count+1)]
       
   144     partition_suite(suite, classes, bins)
       
   145     for i in range(class_count):
       
   146         bins[0].addTests(bins[i+1])
       
   147     return bins[0]
       
   148 
       
   149 def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]):
       
   150     """
       
   151     Run the unit tests for all the test labels in the provided list.
       
   152     Labels must be of the form:
       
   153      - app.TestClass.test_method
       
   154         Run a single specific test method
       
   155      - app.TestClass
       
   156         Run all the test methods in a given class
       
   157      - app
       
   158         Search for doctests and unittests in the named application.
       
   159 
       
   160     When looking for tests, the test runner will look in the models and
       
   161     tests modules for the application.
       
   162 
       
   163     A list of 'extra' tests may also be provided; these tests
       
   164     will be added to the test suite.
       
   165 
       
   166     Returns the number of tests that failed.
       
   167     """
       
   168     setup_test_environment()
       
   169 
       
   170     settings.DEBUG = False
       
   171     suite = unittest.TestSuite()
       
   172 
       
   173     if test_labels:
       
   174         for label in test_labels:
       
   175             if '.' in label:
       
   176                 suite.addTest(build_test(label))
       
   177             else:
       
   178                 app = get_app(label)
       
   179                 suite.addTest(build_suite(app))
       
   180     else:
       
   181         for app in get_apps():
       
   182             suite.addTest(build_suite(app))
       
   183 
       
   184     for test in extra_tests:
       
   185         suite.addTest(test)
       
   186 
       
   187     suite = reorder_suite(suite, (TestCase,))
       
   188 
       
   189     old_name = settings.DATABASE_NAME
       
   190     from django.db import connection
       
   191     connection.creation.create_test_db(verbosity, autoclobber=not interactive)
       
   192     result = unittest.TextTestRunner(verbosity=verbosity).run(suite)
       
   193     connection.creation.destroy_test_db(old_name, verbosity)
       
   194 
       
   195     teardown_test_environment()
       
   196 
       
   197     return len(result.failures) + len(result.errors)