From aef019de6113e6c750e3ba49dc1e9f2a179eb0ca Mon Sep 17 00:00:00 2001 From: Preston Timmons Date: Mon, 16 Dec 2013 10:04:28 -0600 Subject: [PATCH] Fixed #21206 -- No longer run discovery if the test label doesn't point to a package or directory. Thanks thepapermen for the report and Carl Meyer for the review. --- django/test/runner.py | 21 +++++++++++++--- tests/test_discovery_sample/empty.py | 0 tests/test_discovery_sample/tests_sample.py | 4 +++ tests/test_runner/test_discover_runner.py | 28 +++++++++++++++++++++ 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 tests/test_discovery_sample/empty.py diff --git a/django/test/runner.py b/django/test/runner.py index 21e4a81604..d8994d5ec2 100644 --- a/django/test/runner.py +++ b/django/test/runner.py @@ -1,3 +1,4 @@ +from importlib import import_module import os from optparse import make_option import unittest @@ -89,11 +90,11 @@ class DiscoverRunner(object): break kwargs['top_level_dir'] = top_level - if not (tests and tests.countTestCases()): - # if no tests found, it's probably a package; try discovery + if not (tests and tests.countTestCases()) and is_discoverable(label): + # Try discovery if path is a package or directory tests = self.test_loader.discover(start_dir=label, **kwargs) - # make unittest forget the top-level dir it calculated from this + # Make unittest forget the top-level dir it calculated from this # run, to support running tests from two different top-levels. self.test_loader._top_level_dir = None @@ -150,6 +151,20 @@ class DiscoverRunner(object): return self.suite_result(suite, result) +def is_discoverable(label): + """ + Check if a test label points to a python package or file directory. + """ + try: + mod = import_module(label) + except ImportError: + pass + else: + return hasattr(mod, '__path__') + + return os.path.isdir(os.path.abspath(label)) + + def dependency_ordered(test_databases, dependencies): """ Reorder test_databases into an order that honors the dependencies diff --git a/tests/test_discovery_sample/empty.py b/tests/test_discovery_sample/empty.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/test_discovery_sample/tests_sample.py b/tests/test_discovery_sample/tests_sample.py index fb1e14c715..d538771b0f 100644 --- a/tests/test_discovery_sample/tests_sample.py +++ b/tests/test_discovery_sample/tests_sample.py @@ -13,3 +13,7 @@ class TestDjangoTestCase(DjangoTestCase): def test_sample(self): self.assertEqual(1, 1) + + +class EmptyTestCase(TestCase): + pass diff --git a/tests/test_runner/test_discover_runner.py b/tests/test_runner/test_discover_runner.py index d577f26826..fd68949678 100644 --- a/tests/test_runner/test_discover_runner.py +++ b/tests/test_runner/test_discover_runner.py @@ -68,6 +68,34 @@ class DiscoverRunnerTest(TestCase): self.assertEqual(count, 3) + def test_empty_test_case(self): + count = DiscoverRunner().build_suite( + ["test_discovery_sample.tests_sample.EmptyTestCase"], + ).countTestCases() + + self.assertEqual(count, 0) + + def test_discovery_on_package(self): + count = DiscoverRunner().build_suite( + ["test_discovery_sample.tests"], + ).countTestCases() + + self.assertEqual(count, 1) + + def test_ignore_adjacent(self): + """ + When given a dotted path to a module, unittest discovery searches + not just the module, but also the directory containing the module. + + This results in tests from adjacent modules being run when they + should not. The discover runner avoids this behavior. + """ + count = DiscoverRunner().build_suite( + ["test_discovery_sample.empty"], + ).countTestCases() + + self.assertEqual(count, 0) + def test_overrideable_test_suite(self): self.assertEqual(DiscoverRunner().test_suite, TestSuite)