]> granicus.if.org Git - python/commitdiff
#14533: if a test has no test_main, use loadTestsFromModule.
authorR David Murray <rdmurray@bitdance.com>
Mon, 9 Apr 2012 12:55:42 +0000 (08:55 -0400)
committerR David Murray <rdmurray@bitdance.com>
Mon, 9 Apr 2012 12:55:42 +0000 (08:55 -0400)
This moves us further in the direction of using normal unittest facilities
instead of specialized regrtest ones.  Any test module that can be correctly
run currently using 'python unittest -m test.test_xxx' can now be converted to
use normal unittest test loading by simply deleting its test_main, thus no
longer requiring manual maintenance of the list of tests to run.  (Not all
tests can be converted that easily, since test_main sometimes does some
additional things (such as reap_children or reap_threads).  In those cases the
extra code may be moved to setUpModule/tearDownModule methods, or perhaps the
same ends can be achieved in a different way, such as moving the decorators to
the test classes that need them, etc.)

I don't advocate going through and making this change wholesale, but any time
a list of tests in test_main would otherwise need to be updated, consideration
should instead be given to deleting test_main.

Doc/library/test.rst
Lib/test/regrtest.py
Misc/NEWS

index 5e4a1cb9cca2aa3f113a5409a5b5bd2acd329c7d..af9ce451867ab95ffcc42b4243ad4afa241db729 100644 (file)
@@ -80,17 +80,12 @@ A basic boilerplate is often used::
 
    ... more test classes ...
 
-   def test_main():
-       support.run_unittest(MyTestCase1,
-                                 MyTestCase2,
-                                 ... list other tests ...
-                                )
-
    if __name__ == '__main__':
-       test_main()
+       unittest.main()
 
-This boilerplate code allows the testing suite to be run by :mod:`test.regrtest`
-as well as on its own as a script.
+This code pattern allows the testing suite to be run by :mod:`test.regrtest`,
+on its own as a script that supports the :mod:`unittest` CLI, or via the
+`python -m unittest` CLI.
 
 The goal for regression testing is to try to break code. This leads to a few
 guidelines to be followed:
@@ -129,22 +124,27 @@ guidelines to be followed:
   as what type of input is used. Minimize code duplication by subclassing a
   basic test class with a class that specifies the input::
 
-     class TestFuncAcceptsSequences(unittest.TestCase):
+     class TestFuncAcceptsSequencesMixin:
 
          func = mySuperWhammyFunction
 
          def test_func(self):
              self.func(self.arg)
 
-     class AcceptLists(TestFuncAcceptsSequences):
+     class AcceptLists(TestFuncAcceptsSequencesMixin, unittest.TestCase):
          arg = [1, 2, 3]
 
-     class AcceptStrings(TestFuncAcceptsSequences):
+     class AcceptStrings(TestFuncAcceptsSequencesMixin, unittest.TestCase):
          arg = 'abc'
 
-     class AcceptTuples(TestFuncAcceptsSequences):
+     class AcceptTuples(TestFuncAcceptsSequencesMixin, unittest.TestCase):
          arg = (1, 2, 3)
 
+  When using this pattern, remember that all classes that inherit from
+  `unittest.TestCase` are run as tests.  The `Mixin` class in the example above
+  does not have any data and so can't be run by itself, thus it does not
+  inherit from `unittest.TestCase`.
+
 
 .. seealso::
 
@@ -164,10 +164,12 @@ test.regrtest` used in previous Python versions still works).
 Running the script by itself automatically starts running all regression
 tests in the :mod:`test` package. It does this by finding all modules in the
 package whose name starts with ``test_``, importing them, and executing the
-function :func:`test_main` if present. The names of tests to execute may also
+function :func:`test_main` if present or loading the tests via
+unittest.TestLoader.loadTestsFromModule if ``test_main`` does not exist.
+The names of tests to execute may also
 be passed to the script. Specifying a single regression test (:program:`python
 -m test test_spam`) will minimize output and only print
-whether the test passed or failed and thus minimize output.
+whether the test passed or failed.
 
 Running :mod:`test` directly allows what resources are available for
 tests to use to be set. You do this by using the ``-u`` command-line
index 44d3426f53c5ade17c46a7bec739e21653d53051..26066078b6bf9da8137e72752d05cd0b2b5f96ec 100755 (executable)
@@ -1228,14 +1228,15 @@ def runtest_inner(test, verbose, quiet,
             start_time = time.time()
             the_package = __import__(abstest, globals(), locals(), [])
             the_module = getattr(the_package, test)
-            # Old tests run to completion simply as a side-effect of
-            # being imported.  For tests based on unittest or doctest,
-            # explicitly invoke their test_main() function (if it exists).
-            indirect_test = getattr(the_module, "test_main", None)
-            if indirect_test is not None:
-                indirect_test()
+            # If the test has a test_main, that will run the appropriate
+            # tests.  If not, use normal unittest test loading.
+            test_runner = getattr(the_module, "test_main", None)
+            if test_runner is None:
+                tests = unittest.TestLoader().loadTestsFromModule(the_module)
+                test_runner = lambda: support.run_unittest(tests)
+            test_runner()
             if huntrleaks:
-                refleak = dash_R(the_module, test, indirect_test,
+                refleak = dash_R(the_module, test, test_runner,
                     huntrleaks)
             test_time = time.time() - start_time
     except support.ResourceDenied as msg:
index 4c3758d915c867b11e724d7295a2a94c9deb8e4e..3585764bcc2696fd18a2ff3eb67caa9f3d70825d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -51,6 +51,12 @@ Library
 
 - Issue #14493: Use gvfs-open or xdg-open in webbrowser.
 
+Tests
+-----
+
+- Issue #14355: Regrtest now supports the standard unittest test loading, and
+  will use it if a test file contains no `test_main` method.
+
 
 What's New in Python 3.3.0 Alpha 2?
 ===================================