summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrançois Freitag <mail@franek.fr>2019-03-07 21:58:30 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-04-30 16:20:51 +0200
commit568eed9e79470b9ddf3e1b3bbad9123ada45eae8 (patch)
tree6606bd5bad518d0aed7f892148f4aa8fbf4188cf
parent719b7466203181066d9537d2e3bec687dffc9f41 (diff)
Fixed #30245 -- Added -k option to DiscoverRunner.
-rw-r--r--django/test/runner.py23
-rw-r--r--docs/ref/django-admin.txt14
-rw-r--r--docs/releases/3.0.txt6
-rw-r--r--docs/topics/testing/advanced.txt5
-rwxr-xr-xtests/runtests.py16
-rw-r--r--tests/test_runner/test_discover_runner.py40
-rw-r--r--tests/test_runner_apps/simple/tests.py3
7 files changed, 99 insertions, 8 deletions
diff --git a/django/test/runner.py b/django/test/runner.py
index 4f755c8fc5..85a7cd1265 100644
--- a/django/test/runner.py
+++ b/django/test/runner.py
@@ -17,6 +17,7 @@ from django.test.utils import (
teardown_databases as _teardown_databases, teardown_test_environment,
)
from django.utils.datastructures import OrderedSet
+from django.utils.version import PY37
try:
import tblib.pickling_support
@@ -407,7 +408,7 @@ class DiscoverRunner:
def __init__(self, pattern=None, top_level=None, verbosity=1,
interactive=True, failfast=False, keepdb=False,
reverse=False, debug_mode=False, debug_sql=False, parallel=0,
- tags=None, exclude_tags=None, **kwargs):
+ tags=None, exclude_tags=None, test_name_patterns=None, **kwargs):
self.pattern = pattern
self.top_level = top_level
@@ -421,6 +422,14 @@ class DiscoverRunner:
self.parallel = parallel
self.tags = set(tags or [])
self.exclude_tags = set(exclude_tags or [])
+ self.test_name_patterns = None
+ if test_name_patterns:
+ # unittest does not export the _convert_select_pattern function
+ # that converts command-line arguments to patterns.
+ self.test_name_patterns = {
+ pattern if '*' in pattern else '*%s*' % pattern
+ for pattern in test_name_patterns
+ }
@classmethod
def add_arguments(cls, parser):
@@ -433,7 +442,7 @@ class DiscoverRunner:
help='The test matching pattern. Defaults to test*.py.',
)
parser.add_argument(
- '-k', '--keepdb', action='store_true',
+ '--keepdb', action='store_true',
help='Preserves the test DB between runs.'
)
parser.add_argument(
@@ -461,6 +470,15 @@ class DiscoverRunner:
'--exclude-tag', action='append', dest='exclude_tags',
help='Do not run tests with the specified tag. Can be used multiple times.',
)
+ if PY37:
+ parser.add_argument(
+ '-k', action='append', dest='test_name_patterns',
+ help=(
+ 'Only run test methods and classes that match the pattern '
+ 'or substring. Can be used multiple times. Same as '
+ 'unittest -k option.'
+ ),
+ )
def setup_test_environment(self, **kwargs):
setup_test_environment(debug=self.debug_mode)
@@ -470,6 +488,7 @@ class DiscoverRunner:
suite = self.test_suite()
test_labels = test_labels or ['.']
extra_tests = extra_tests or []
+ self.test_loader.testNamePatterns = self.test_name_patterns
discover_kwargs = {}
if self.pattern is not None:
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
index a269f6f8c6..4c7396f929 100644
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -1360,7 +1360,7 @@ The ``test`` command receives options on behalf of the specified
:option:`--testrunner`. These are the options of the default test runner:
:class:`~django.test.runner.DiscoverRunner`.
-.. django-admin-option:: --keepdb, -k
+.. django-admin-option:: --keepdb
Preserves the test database between test runs. This has the advantage of
skipping both the create and destroy actions which can greatly decrease the
@@ -1438,6 +1438,18 @@ May be specified multiple times and combined with :option:`test --exclude-tag`.
Excludes tests :ref:`marked with the specified tags <topics-tagging-tests>`.
May be specified multiple times and combined with :option:`test --tag`.
+.. django-admin-option:: -k TEST_NAME_PATTERNS
+
+.. versionadded:: 3.0
+
+Runs test methods and classes matching test name patterns, in the same way as
+:option:`unittest's -k option<unittest.-k>`. Can be specified multiple times.
+
+.. admonition:: Python 3.7 and later
+
+ This feature is only available for Python 3.7 and later.
+
+
``testserver``
--------------
diff --git a/docs/releases/3.0.txt b/docs/releases/3.0.txt
index 66dfde0b5d..b78d4bd6ab 100644
--- a/docs/releases/3.0.txt
+++ b/docs/releases/3.0.txt
@@ -238,6 +238,9 @@ Tests
attribute :attr:`~django.test.Response.exc_info`, a tuple providing
information of the exception that occurred.
+* Tests and test cases to run can be selected by test name pattern using the
+ new :option:`test -k` option.
+
URLs
~~~~
@@ -360,6 +363,9 @@ Miscellaneous
This converts ``'`` to ``&#x27;`` instead of the previous equivalent decimal
code ``&#39;``.
+* The ``django-admin test -k`` option now works as the :option:`unittest
+ -k<unittest.-k>` option rather than as a shortcut for ``--keepdb``.
+
.. _deprecated-features-3.0:
Features deprecated in 3.0
diff --git a/docs/topics/testing/advanced.txt b/docs/topics/testing/advanced.txt
index 0a228fc4ef..2e4171d376 100644
--- a/docs/topics/testing/advanced.txt
+++ b/docs/topics/testing/advanced.txt
@@ -424,7 +424,7 @@ behavior. This class defines the ``run_tests()`` entry point, plus a
selection of other methods that are used to by ``run_tests()`` to set up,
execute and tear down the test suite.
-.. class:: DiscoverRunner(pattern='test*.py', top_level=None, verbosity=1, interactive=True, failfast=False, keepdb=False, reverse=False, debug_mode=False, debug_sql=False, **kwargs)
+.. class:: DiscoverRunner(pattern='test*.py', top_level=None, verbosity=1, interactive=True, failfast=False, keepdb=False, reverse=False, debug_mode=False, debug_sql=False, test_name_patterns=None, **kwargs)
``DiscoverRunner`` will search for tests in any file matching ``pattern``.
@@ -463,6 +463,9 @@ execute and tear down the test suite.
as the traceback. If ``verbosity`` is ``2``, then queries in all tests are
output.
+ ``test_name_patterns`` can be used to specify a set of patterns for
+ filtering test methods and classes by their names.
+
Django may, from time to time, extend the capabilities of the test runner
by adding new arguments. The ``**kwargs`` declaration allows for this
expansion. If you subclass ``DiscoverRunner`` or write your own test
diff --git a/tests/runtests.py b/tests/runtests.py
index a0b429b6df..96ec30d51a 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -28,6 +28,7 @@ else:
RemovedInDjango31Warning, RemovedInDjango40Warning,
)
from django.utils.log import DEFAULT_LOGGING
+ from django.utils.version import PY37
try:
import MySQLdb
@@ -271,7 +272,8 @@ class ActionSelenium(argparse.Action):
def django_tests(verbosity, interactive, failfast, keepdb, reverse,
- test_labels, debug_sql, parallel, tags, exclude_tags):
+ test_labels, debug_sql, parallel, tags, exclude_tags,
+ test_name_patterns):
state = setup(verbosity, test_labels, parallel)
extra_tests = []
@@ -290,6 +292,7 @@ def django_tests(verbosity, interactive, failfast, keepdb, reverse,
parallel=actual_test_processes(parallel),
tags=tags,
exclude_tags=exclude_tags,
+ test_name_patterns=test_name_patterns,
)
failures = test_runner.run_tests(
test_labels or get_installed(),
@@ -416,7 +419,7 @@ if __name__ == "__main__":
help='Tells Django to stop running the test suite after first failed test.',
)
parser.add_argument(
- '-k', '--keepdb', action='store_true',
+ '--keepdb', action='store_true',
help='Tells Django to preserve the test database between runs.',
)
parser.add_argument(
@@ -469,6 +472,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.',
)
+ if PY37:
+ parser.add_argument(
+ '-k', dest='test_name_patterns', action='append',
+ help=(
+ 'Only run test methods and classes matching test name pattern. '
+ 'Same as unittest -k option. Can be used multiple times.'
+ ),
+ )
options = parser.parse_args()
@@ -507,6 +518,7 @@ if __name__ == "__main__":
options.keepdb, options.reverse, options.modules,
options.debug_sql, options.parallel, options.tags,
options.exclude_tags,
+ getattr(options, 'test_name_patterns', None),
)
if failures:
sys.exit(1)
diff --git a/tests/test_runner/test_discover_runner.py b/tests/test_runner/test_discover_runner.py
index caa48a852d..160f174b76 100644
--- a/tests/test_runner/test_discover_runner.py
+++ b/tests/test_runner/test_discover_runner.py
@@ -1,12 +1,13 @@
import os
from argparse import ArgumentParser
from contextlib import contextmanager
-from unittest import TestSuite, TextTestRunner, defaultTestLoader
+from unittest import TestSuite, TextTestRunner, defaultTestLoader, skipUnless
from django.db import connections
from django.test import SimpleTestCase
from django.test.runner import DiscoverRunner
from django.test.utils import captured_stdout
+from django.utils.version import PY37
@contextmanager
@@ -23,6 +24,13 @@ def change_cwd(directory):
class DiscoverRunnerTests(SimpleTestCase):
+ @staticmethod
+ def get_test_methods_names(suite):
+ return [
+ t.__class__.__name__ + '.' + t._testMethodName
+ for t in suite._tests
+ ]
+
def test_init_debug_mode(self):
runner = DiscoverRunner()
self.assertFalse(runner.debug_mode)
@@ -71,6 +79,34 @@ class DiscoverRunnerTests(SimpleTestCase):
self.assertEqual(count, 1)
+ @skipUnless(PY37, 'unittest -k option requires Python 3.7 and later')
+ def test_name_patterns(self):
+ all_test_1 = [
+ 'DjangoCase1.test_1', 'DjangoCase2.test_1',
+ 'SimpleCase1.test_1', 'SimpleCase2.test_1',
+ 'UnittestCase1.test_1', 'UnittestCase2.test_1',
+ ]
+ all_test_2 = [
+ 'DjangoCase1.test_2', 'DjangoCase2.test_2',
+ 'SimpleCase1.test_2', 'SimpleCase2.test_2',
+ 'UnittestCase1.test_2', 'UnittestCase2.test_2',
+ ]
+ all_tests = sorted([*all_test_1, *all_test_2, 'UnittestCase2.test_3_test'])
+ for pattern, expected in [
+ [['test_1'], all_test_1],
+ [['UnittestCase1'], ['UnittestCase1.test_1', 'UnittestCase1.test_2']],
+ [['*test'], ['UnittestCase2.test_3_test']],
+ [['test*'], all_tests],
+ [['test'], all_tests],
+ [['test_1', 'test_2'], sorted([*all_test_1, *all_test_2])],
+ [['test*1'], all_test_1],
+ ]:
+ with self.subTest(pattern):
+ suite = DiscoverRunner(
+ test_name_patterns=pattern
+ ).build_suite(['test_runner_apps.simple'])
+ self.assertEqual(expected, self.get_test_methods_names(suite))
+
def test_file_path(self):
with change_cwd(".."):
count = DiscoverRunner().build_suite(
@@ -170,7 +206,7 @@ class DiscoverRunnerTests(SimpleTestCase):
msg="Methods of Django cases should be reversed.")
self.assertIn('test_2', suite[4].id(),
msg="Methods of simple cases should be reversed.")
- self.assertIn('test_2', suite[8].id(),
+ self.assertIn('test_2', suite[9].id(),
msg="Methods of unittest cases should be reversed.")
def test_overridable_get_test_runner_kwargs(self):
diff --git a/tests/test_runner_apps/simple/tests.py b/tests/test_runner_apps/simple/tests.py
index ac3e9daba0..edd822737c 100644
--- a/tests/test_runner_apps/simple/tests.py
+++ b/tests/test_runner_apps/simple/tests.py
@@ -55,3 +55,6 @@ class UnittestCase2(TestCase):
def test_2(self):
pass
+
+ def test_3_test(self):
+ pass