From 6ca964286c671a43a1d28302174ca0b20cfedb9c Mon Sep 17 00:00:00 2001 From: Patrick Gerken Date: Wed, 17 Dec 2014 12:04:25 +0100 Subject: [PATCH] fix(findcode): better finding of test code This fix sorts the --paths to look for code. Longest paths come first. This is for cases where one checks out other sources within his source directory. In such a case this structure can happen: my_package my_package/src/some_other_package Now when my_package gets found first. It logs an import error and then goes on. by sorting with longest paths first. I always get the most specific match first. Since the loop is short circuited here, it will never look at my_package. This fixes #15 --- CHANGES.rst | 3 ++- src/zope/testrunner/find.py | 7 +++++- src/zope/testrunner/tests/test_doctest.py | 1 + .../testrunner/tests/testrunner-discovery.txt | 23 +++++++++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index f5cee20..d573554 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,8 @@ zope.testrunner Changelog 4.4.4 (unreleased) ================== -- TBD +- When looking for the right location of test code, start with longest + location paths first. This fixes problems with nested code locations. 4.4.3 (2014-03-19) diff --git a/src/zope/testrunner/find.py b/src/zope/testrunner/find.py index 6a3718b..cbbdedd 100644 --- a/src/zope/testrunner/find.py +++ b/src/zope/testrunner/find.py @@ -171,8 +171,13 @@ def find_tests(options, found_suites=None): def find_suites(options): + # Sort prefixes so that longest prefixes come first. + # That is because only first match is evaluated which + # can be a problem with nested source packages. + sorted_prefixes = [x for x in options.prefix] + sorted_prefixes.sort(key=lambda prefix: len(prefix[0]), reverse=True) for fpath, package in find_test_files(options): - for (prefix, prefix_package) in options.prefix: + for (prefix, prefix_package) in sorted_prefixes: if fpath.startswith(prefix) and package == prefix_package: # strip prefix, strip .py suffix and convert separator to dots noprefix = fpath[len(prefix):] diff --git a/src/zope/testrunner/tests/test_doctest.py b/src/zope/testrunner/tests/test_doctest.py index 7e029ae..c181dfa 100644 --- a/src/zope/testrunner/tests/test_doctest.py +++ b/src/zope/testrunner/tests/test_doctest.py @@ -213,6 +213,7 @@ def test_suite(): 'testrunner-progress.txt', 'testrunner-colors.txt', 'testrunner-simple.txt', + 'testrunner-nestedcode.txt', 'testrunner-test-selection.txt', 'testrunner-verbose.txt', 'testrunner-repeat.txt', diff --git a/src/zope/testrunner/tests/testrunner-discovery.txt b/src/zope/testrunner/tests/testrunner-discovery.txt index 06ca637..e841477 100644 --- a/src/zope/testrunner/tests/testrunner-discovery.txt +++ b/src/zope/testrunner/tests/testrunner-discovery.txt @@ -46,3 +46,26 @@ testrunner will exit with an error to prevent acidentally missing test cases: sample1.sampletests_discover_notests Total: 0 tests, 0 failures, 0 errors and 0 skipped in 0.000 seconds. True + +You can explicitly specify which tests to run by providing a function that +returns a unittest.TestSuite in the test modules (the name of the function can +be configured with the --suite-name parameter, it defaults to 'test_suite'). If +no such function is present, testrunner will use all classes in the module that +inherit from unittest.TestCase as tests: + + >>> import os, sys + >>> directory_with_tests = os.path.join(this_directory, 'testrunner-ex') + + >>> from zope import testrunner + + >>> defaults = [ + ... ] + >>> sys.argv = ['test', + ... ] + >>> testrunner.run(defaults) + Running zope.testrunner.layer.UnitTests tests: + Set up zope.testrunner.layer.UnitTests in N.NNN seconds. + Ran 2 tests with 0 failures, 0 errors and 0 skipped in N.NNN seconds. + Tearing down left over layers: + Tear down zope.testrunner.layer.UnitTests in N.NNN seconds. + False