Reputation: 52333
With this question I worked out how to break my tests over multiple files. So now in each file/module I have a series of TestCase classes.
I can still invoke individual TestCases by explicitly naming them from the command line like:
./manage.py test api.TokenGeneratorTestCase api.ViewsTestCase
Rather than invoking related TestCase's individually, now I'm thinking it would be nice to group the related TestCases into Suites, and then invoke the whole Suite from the commandline; hopefully without loosing the ability to invoke all the Suites in the app at once.
I've seen this python stuff about suites, and also this django stuff about suites, but working out how to do what I want is elusive. I think I'm looking to be able to say things like:
./manage.py test api.NewSeedsImportTestCase api.NewSeedsExportTestCase
./manage.py test api.NewSeedsSuite
./manage.py test api.NewRoomsSuite
./manage.py test api
Has anyone out there arranged their Django TestCases into Suites and can show me how?
Upvotes: 2
Views: 513
Reputation: 16252
One possible approach is to write a custom runner that would extend django.test.simple.DjangoTestSuiteRunner
and override the build_suite
method. That's where Django generates the suite used by the test
command.
It gets an argument test_labels
which corresponds to the command line arguments passed to the command. You can extend its functionality by allowing passing extra module paths from where tests should be loaded. Something like this should do the trick (this is just to demonstrate the approach, I haven't tested the code):
from django.test.simple import DjangoTestSuiteRunner
from django.utils import unittest
from django.utils.importlib import import_module
class MyTestSuiteRunner(DjangoTestSuiteRunner):
def build_suite(self, test_labels, extra_tests=None, *args, **kwargs):
if test_labels:
extra_test_modules = [label.lstrip('module:')
for label in test_labels
if label.startswith('module:')]
extra_tests = extra_tests or []
for module_path in extra_test_modules:
# Better way to load the tests here would probably be to use
# `django.test.siple.build_suite` as it does some extra stuff like looking for doctests.
extra_tests += unittest.defaultTestLoader.loadTestsFromModule(import_module(module_path))
# Remove the 'module:*' labels
test_labels = [label for label in test_labels if not label.startswith('module:')]
# Let Django do the rest
return super(MyTestSuiteRunner, self).build_suite(test_labels, extra_tests, *args, **kwargs)
Now you should be able to run the test
command exactly as before, except that any label that looks like this module:api.test.extra
will result in all the tests/suites from the module being added to the final suite.
Note that the 'module:' labels are not app labels so that it must be a full python path to the module.
You will also need to point your TEST_RUNNER
settings to your new test runner.
Upvotes: 1