11import unittest
22from django .conf import settings
3+ from django .db .models import get_app , get_apps
34from django .test import _doctest as doctest
45from django .test .utils import setup_test_environment , teardown_test_environment
56from django .test .utils import create_test_db , destroy_test_db
1011
1112doctestOutputChecker = OutputChecker ()
1213
14+ def get_tests (app_module ):
15+ try :
16+ app_path = app_module .__name__ .split ('.' )[:- 1 ]
17+ test_module = __import__ ('.' .join (app_path + [TEST_MODULE ]), {}, {}, TEST_MODULE )
18+ except ImportError , e :
19+ # Couldn't import tests.py. Was it due to a missing file, or
20+ # due to an import error in a tests.py that actually exists?
21+ import os .path
22+ from imp import find_module
23+ try :
24+ mod = find_module (TEST_MODULE , [os .path .dirname (app_module .__file__ )])
25+ except ImportError :
26+ # 'tests' module doesn't exist. Move on.
27+ test_module = None
28+ else :
29+ # The module exists, so there must be an import error in the
30+ # test module itself. We don't need the module; so if the
31+ # module was a single file module (i.e., tests.py), close the file
32+ # handle returned by find_module. Otherwise, the test module
33+ # is a directory, and there is nothing to close.
34+ if mod [0 ]:
35+ mod [0 ].close ()
36+ raise
37+ return test_module
38+
1339def build_suite (app_module ):
1440 "Create a complete Django test suite for the provided application module"
1541 suite = unittest .TestSuite ()
@@ -30,10 +56,8 @@ def build_suite(app_module):
3056
3157 # Check to see if a separate 'tests' module exists parallel to the
3258 # models module
33- try :
34- app_path = app_module .__name__ .split ('.' )[:- 1 ]
35- test_module = __import__ ('.' .join (app_path + [TEST_MODULE ]), {}, {}, TEST_MODULE )
36-
59+ test_module = get_tests (app_module )
60+ if test_module :
3761 # Load unit and doctests in the tests.py module. If module has
3862 # a suite() method, use it. Otherwise build the test suite ourselves.
3963 if hasattr (test_module , 'suite' ):
@@ -47,34 +71,50 @@ def build_suite(app_module):
4771 except ValueError :
4872 # No doc tests in tests.py
4973 pass
50- except ImportError , e :
51- # Couldn't import tests.py. Was it due to a missing file, or
52- # due to an import error in a tests.py that actually exists?
53- import os .path
54- from imp import find_module
55- try :
56- mod = find_module (TEST_MODULE , [os .path .dirname (app_module .__file__ )])
57- except ImportError :
58- # 'tests' module doesn't exist. Move on.
59- pass
60- else :
61- # The module exists, so there must be an import error in the
62- # test module itself. We don't need the module; so if the
63- # module was a single file module (i.e., tests.py), close the file
64- # handle returned by find_module. Otherwise, the test module
65- # is a directory, and there is nothing to close.
66- if mod [0 ]:
67- mod [0 ].close ()
68- raise
69-
7074 return suite
7175
72- def run_tests (module_list , verbosity = 1 , interactive = True , extra_tests = []):
76+ def build_test (label ):
77+ """Construct a test case a test with the specified label. Label should
78+ be of the form model.TestClass or model.TestClass.test_method. Returns
79+ an instantiated test or test suite corresponding to the label provided.
80+
81+ """
82+ parts = label .split ('.' )
83+ if len (parts ) < 2 or len (parts ) > 3 :
84+ raise ValueError ("Test label '%s' should be of the form app.TestCase or app.TestCase.test_method" % label )
85+
86+ app_module = get_app (parts [0 ])
87+ TestClass = getattr (app_module , parts [1 ], None )
88+
89+ # Couldn't find the test class in models.py; look in tests.py
90+ if TestClass is None :
91+ test_module = get_tests (app_module )
92+ if test_module :
93+ TestClass = getattr (test_module , parts [1 ], None )
94+
95+ if len (parts ) == 2 : # label is app.TestClass
96+ try :
97+ return unittest .TestLoader ().loadTestsFromTestCase (TestClass )
98+ except TypeError :
99+ raise ValueError ("Test label '%s' does not refer to a test class" % label )
100+ else : # label is app.TestClass.test_method
101+ return TestClass (parts [2 ])
102+
103+ def run_tests (test_labels , verbosity = 1 , interactive = True , extra_tests = []):
73104 """
74- Run the unit tests for all the modules in the provided list.
75- This testrunner will search each of the modules in the provided list,
76- looking for doctests and unittests in models.py or tests.py within
77- the module. A list of 'extra' tests may also be provided; these tests
105+ Run the unit tests for all the test labels in the provided list.
106+ Labels must be of the form:
107+ - app.TestClass.test_method
108+ Run a single specific test method
109+ - app.TestClass
110+ Run all the test methods in a given class
111+ - app
112+ Search for doctests and unittests in the named application.
113+
114+ When looking for tests, the test runner will look in the models and
115+ tests modules for the application.
116+
117+ A list of 'extra' tests may also be provided; these tests
78118 will be added to the test suite.
79119
80120 Returns the number of tests that failed.
@@ -83,9 +123,17 @@ def run_tests(module_list, verbosity=1, interactive=True, extra_tests=[]):
83123
84124 settings .DEBUG = False
85125 suite = unittest .TestSuite ()
86-
87- for module in module_list :
88- suite .addTest (build_suite (module ))
126+
127+ if test_labels :
128+ for label in test_labels :
129+ if '.' in label :
130+ suite .addTest (build_test (label ))
131+ else :
132+ app = get_app (label )
133+ suite .addTest (build_suite (app ))
134+ else :
135+ for app in get_apps ():
136+ suite .addTest (build_suite (app ))
89137
90138 for test in extra_tests :
91139 suite .addTest (test )
0 commit comments