summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHasan Ramezani <hasan.r67@gmail.com>2019-05-25 20:55:30 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-05-31 07:01:12 +0200
commite2de49ec2ea5827b36d0d4ec4f90b4ee0a003e93 (patch)
treef1e67da211515557b6fe8789432f5cbf60979d55
parentef7e0ae53bf42942c3dcf1155962b90ab3f3e6fd (diff)
Fixed #28520 -- Added --start-at/--start-after options to runtests.py.
-rw-r--r--docs/internals/contributing/writing-code/unit-tests.txt18
-rw-r--r--docs/releases/3.0.txt3
-rwxr-xr-xtests/runtests.py54
3 files changed, 66 insertions, 9 deletions
diff --git a/docs/internals/contributing/writing-code/unit-tests.txt b/docs/internals/contributing/writing-code/unit-tests.txt
index 6d9074f2d1..febfa3546e 100644
--- a/docs/internals/contributing/writing-code/unit-tests.txt
+++ b/docs/internals/contributing/writing-code/unit-tests.txt
@@ -213,6 +213,24 @@ Going beyond that, you can specify an individual test method like this:
$ ./runtests.py --settings=path.to.settings i18n.tests.TranslationTests.test_lazy_objects
+You can run tests starting at a specified top-level module with ``--start-at``
+option. For example:
+
+.. console::
+
+ $ ./runtests.py --start-at=wsgi
+
+You can also run tests starting after a specified top-level module with
+``--start-after`` option. For example:
+
+.. console::
+
+ $ ./runtests.py --start-after=wsgi
+
+Note that the ``--reverse`` option doesn't impact on ``--start-at`` or
+``--start-after`` options. Moreover these options cannot be used with test
+labels.
+
Running the Selenium tests
--------------------------
diff --git a/docs/releases/3.0.txt b/docs/releases/3.0.txt
index 25d602559e..14156af459 100644
--- a/docs/releases/3.0.txt
+++ b/docs/releases/3.0.txt
@@ -267,6 +267,9 @@ Tests
* Django test runner now supports headless mode for selenium tests on supported
browsers. Add the ``--headless`` option to enable this mode.
+* Django test runner now supports ``--start-at`` and ``--start-after`` options
+ to run tests starting from a specific top-level module.
+
URLs
~~~~
diff --git a/tests/runtests.py b/tests/runtests.py
index cac4fa26e1..153cb0df26 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -116,7 +116,7 @@ def get_installed():
return [app_config.name for app_config in apps.get_app_configs()]
-def setup(verbosity, test_labels, parallel):
+def setup(verbosity, test_labels, parallel, start_at, start_after):
# Reduce the given test labels to just the app module path.
test_labels_set = set()
for label in test_labels:
@@ -202,12 +202,21 @@ def setup(verbosity, test_labels, parallel):
# Load all the test model apps.
test_modules = get_test_modules()
+ found_start = not (start_at or start_after)
installed_app_names = set(get_installed())
for modpath, module_name in test_modules:
if modpath:
module_label = modpath + '.' + module_name
else:
module_label = module_name
+ if not found_start:
+ if start_at and _module_match_label(module_label, start_at):
+ found_start = True
+ elif start_after and _module_match_label(module_label, start_after):
+ found_start = True
+ continue
+ else:
+ continue
# if the module (or an ancestor) was named on the command line, or
# no modules were named (i.e., run all), import
# this module and add it to INSTALLED_APPS.
@@ -275,8 +284,8 @@ class ActionSelenium(argparse.Action):
def django_tests(verbosity, interactive, failfast, keepdb, reverse,
test_labels, debug_sql, parallel, tags, exclude_tags,
- test_name_patterns):
- state = setup(verbosity, test_labels, parallel)
+ test_name_patterns, start_at, start_after):
+ state = setup(verbosity, test_labels, parallel, start_at, start_after)
extra_tests = []
# Run the test suite, including the extra validation tests.
@@ -321,8 +330,8 @@ def get_subprocess_args(options):
return subprocess_args
-def bisect_tests(bisection_label, options, test_labels, parallel):
- state = setup(options.verbosity, test_labels, parallel)
+def bisect_tests(bisection_label, options, test_labels, parallel, start_at, start_after):
+ state = setup(options.verbosity, test_labels, parallel, start_at, start_after)
test_labels = test_labels or get_installed()
@@ -372,8 +381,8 @@ def bisect_tests(bisection_label, options, test_labels, parallel):
teardown(state)
-def paired_tests(paired_test, options, test_labels, parallel):
- state = setup(options.verbosity, test_labels, parallel)
+def paired_tests(paired_test, options, test_labels, parallel, start_at, start_after):
+ state = setup(options.verbosity, test_labels, parallel, start_at, start_after)
test_labels = test_labels or get_installed()
@@ -478,6 +487,14 @@ if __name__ == "__main__":
'--exclude-tag', dest='exclude_tags', action='append',
help='Do not run tests with the specified tag. Can be used multiple times.',
)
+ parser.add_argument(
+ '--start-after', dest='start_after',
+ help='Run tests starting after the specified top-level module.',
+ )
+ parser.add_argument(
+ '--start-at', dest='start_at',
+ help='Run tests starting at the specified top-level module.',
+ )
if PY37:
parser.add_argument(
'-k', dest='test_name_patterns', action='append',
@@ -498,6 +515,18 @@ if __name__ == "__main__":
# Allow including a trailing slash on app_labels for tab completion convenience
options.modules = [os.path.normpath(labels) for labels in options.modules]
+ mutually_exclusive_options = [options.start_at, options.start_after, options.modules]
+ enabled_module_options = [bool(option) for option in mutually_exclusive_options].count(True)
+ if enabled_module_options > 1:
+ print('Aborting: --start-at, --start-after, and test labels are mutually exclusive.')
+ sys.exit(1)
+ for opt_name in ['start_at', 'start_after']:
+ opt_val = getattr(options, opt_name)
+ if opt_val:
+ if '.' in opt_val:
+ print('Aborting: --%s must be a top-level module.' % opt_name.replace('_', '-'))
+ sys.exit(1)
+ setattr(options, opt_name, os.path.normpath(opt_val))
if options.settings:
os.environ['DJANGO_SETTINGS_MODULE'] = options.settings
else:
@@ -516,9 +545,15 @@ if __name__ == "__main__":
SeleniumTestCaseBase.browsers = options.selenium
if options.bisect:
- bisect_tests(options.bisect, options, options.modules, options.parallel)
+ bisect_tests(
+ options.bisect, options, options.modules, options.parallel,
+ options.start_at, options.start_after,
+ )
elif options.pair:
- paired_tests(options.pair, options, options.modules, options.parallel)
+ paired_tests(
+ options.pair, options, options.modules, options.parallel,
+ options.start_at, options.start_after,
+ )
else:
failures = django_tests(
options.verbosity, options.interactive, options.failfast,
@@ -526,6 +561,7 @@ if __name__ == "__main__":
options.debug_sql, options.parallel, options.tags,
options.exclude_tags,
getattr(options, 'test_name_patterns', None),
+ options.start_at, options.start_after,
)
if failures:
sys.exit(1)