Django

Code

Changeset 5769

Show
Ignore:
Timestamp:
07/27/07 23:02:52 (2 years ago)
Author:
russellm
Message:

Fixed #4460 -- Added the ability to be more specific in the test cases that are executed. This is a backwards incompatible change for any user with a custom test runner. See the wiki for details.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/core/management.py

    r5752 r5769  
    13321332runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]' 
    13331333 
    1334 def test(app_labels, verbosity=1, interactive=True): 
     1334def test(test_labels, verbosity=1, interactive=True): 
    13351335    "Runs the test suite for the specified applications" 
    13361336    from django.conf import settings 
    13371337    from django.db.models import get_app, get_apps 
    1338  
    1339     if len(app_labels) == 0: 
    1340         app_list = get_apps() 
    1341     else: 
    1342         app_list = [get_app(app_label) for app_label in app_labels] 
    1343  
     1338     
    13441339    test_path = settings.TEST_RUNNER.split('.') 
    13451340    # Allow for Python 2.5 relative paths 
     
    13511346    test_runner = getattr(test_module, test_path[-1]) 
    13521347 
    1353     failures = test_runner(app_list, verbosity=verbosity, interactive=interactive) 
     1348    failures = test_runner(test_labels, verbosity=verbosity, interactive=interactive) 
    13541349    if failures: 
    13551350        sys.exit(failures) 
  • django/trunk/django/test/simple.py

    r5752 r5769  
    11import unittest 
    22from django.conf import settings 
     3from 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 
     
    1112doctestOutputChecker = OutputChecker() 
    1213 
     14def 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" 
     
    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. 
     
    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=[]): 
     76def 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         
    7381    """ 
    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 
     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 
     103def run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[]): 
     104    """ 
     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     
     
    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: 
  • django/trunk/docs/testing.txt

    r5753 r5769  
    451451            # test definitions as before 
    452452 
     453        def testFluffyAnimals(self): 
     454            # A test that uses the fixtures 
     455 
    453456At the start of each test case, before ``setUp()`` is run, Django will 
    454457flush the database, returning the database the state it was in directly 
     
    484487``assertContains(response, text, count=None, status_code=200)`` 
    485488    Assert that a response indicates that a page could be retrieved and 
    486     produced the nominated status code, and that ``text`` in the content  
    487     of the response. If ``count`` is provided, ``text`` must occur exactly  
     489    produced the nominated status code, and that ``text`` in the content 
     490    of the response. If ``count`` is provided, ``text`` must occur exactly 
    488491    ``count`` times in the response. 
    489492 
     
    571574 
    572575    $ ./manage.py test animals 
     576 
     577**New in Django development version:** If you use unit tests, you can be more 
     578specific in the tests that are executed. To run a single test case in an 
     579application (for example, the AnimalTestCase described previously), add the 
     580name of the test case to the label on the command line:: 
     581 
     582    $ ./manage.py test animals.AnimalTestCase 
     583 
     584**New in Django development version:**To run a single test method inside a 
     585test case, add the name of the test method to the label:: 
     586 
     587    $ ./manage.py test animals.AnimalTestCase.testFluffyAnimals 
    573588 
    574589When you run your tests, you'll see a bunch of text flow by as the test 
     
    666681same arguments as the Django test runner: 
    667682 
    668 ``run_tests(module_list, verbosity=1, interactive=True, extra_tests=[])`` 
    669     The module list is the list of Python modules that contain the models to be 
    670     tested. This is the same format returned by ``django.db.models.get_apps()``. 
    671     The test runner should search these modules for tests to execute. 
     683``run_tests(test_labels, verbosity=1, interactive=True, extra_tests=[])`` 
     684    **New in Django development version:** ``test_labels`` is a list of 
     685    strings describing the tests to be run. A test label can take one of 
     686    three forms: 
     687        * ``app.TestCase.test_method`` - Run a single test method in a test case 
     688        * ``app.TestCase`` - Run all the test methods in a test case 
     689        * ``app`` - Search for and run all tests in the named application. 
     690    If ``test_labels`` has a value of ``None``, the test runner should run 
     691    search for tests in all the applications in ``INSTALLED_APPS``. 
    672692 
    673693    Verbosity determines the amount of notification and debug information that 
     
    675695    and ``2`` is verbose output. 
    676696 
    677     **New in Django development version** If ``interactive`` is ``True``, the 
     697    **New in Django development version:** If ``interactive`` is ``True``, the 
    678698    test suite may ask the user for instructions when the test suite is 
    679699    executed. An example of this behavior would be asking for permission to 
    680     delete an existing test database. If ``interactive`` is ``False, the  
     700    delete an existing test database. If ``interactive`` is ``False, the 
    681701    test suite must be able to run without any manual intervention. 
    682      
    683     ``extra_tests`` is a list of extra ``TestCase`` instances to add to the  
    684     suite that is executed by the test runner. These extra tests are run  
     702 
     703    ``extra_tests`` is a list of extra ``TestCase`` instances to add to the 
     704    suite that is executed by the test runner. These extra tests are run 
    685705    in addition to those discovered in the modules listed in ``module_list``. 
    686      
     706 
    687707    This method should return the number of tests that failed. 
    688708 
  • django/trunk/tests/runtests.py

    r5752 r5769  
    7474        self.assert_(not missing, "Missing Errors: " + '\n'.join(missing)) 
    7575 
    76 def django_tests(verbosity, interactive, tests_to_run): 
     76def django_tests(verbosity, interactive, test_labels): 
    7777    from django.conf import settings 
    7878 
     
    110110            # no models were named (i.e., run all), import 
    111111            # this model and add it to the list to test. 
    112             if not tests_to_run or model_name in tests_to_run
     112            if not test_labels or model_name in set([label.split('.')[0] for label in test_labels])
    113113                if verbosity >= 1: 
    114114                    print "Importing model %s" % model_name 
     
    117117                    if model_label not in settings.INSTALLED_APPS: 
    118118                        settings.INSTALLED_APPS.append(model_label) 
    119                     test_models.append(mod) 
    120119        except Exception, e: 
    121120            sys.stderr.write("Error while importing %s:" % model_name + ''.join(traceback.format_exception(*sys.exc_info())[1:])) 
     
    126125    for model_dir, model_name in get_invalid_models(): 
    127126        model_label = '.'.join([model_dir, model_name]) 
    128         if not tests_to_run or model_name in tests_to_run
     127        if not test_labels or model_name in test_labels
    129128            extra_tests.append(InvalidModelTestCase(model_label)) 
    130129 
    131130    # Run the test suite, including the extra validation tests. 
    132131    from django.test.simple import run_tests 
    133     failures = run_tests(test_models, verbosity=verbosity, interactive=interactive, extra_tests=extra_tests) 
     132    failures = run_tests(test_labels, verbosity=verbosity, interactive=interactive, extra_tests=extra_tests) 
    134133    if failures: 
    135134        sys.exit(failures)