[Python-checkins] cpython (3.3): Remove cruft and circumvolutions from the unittest docs.

antoine.pitrou python-checkins at python.org
Sun Jan 20 01:34:02 CET 2013


http://hg.python.org/cpython/rev/0a2e8e18ee94
changeset:   81606:0a2e8e18ee94
branch:      3.3
parent:      81602:5b774459571c
user:        Antoine Pitrou <solipsis at pitrou.net>
date:        Sun Jan 20 01:29:39 2013 +0100
summary:
  Remove cruft and circumvolutions from the unittest docs.
(I would have preferred to post this for review but the bug tracker is pretty much dead at the moment)

files:
  Doc/library/unittest.rst |  261 ++++++--------------------
  1 files changed, 60 insertions(+), 201 deletions(-)


diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst
--- a/Doc/library/unittest.rst
+++ b/Doc/library/unittest.rst
@@ -11,17 +11,14 @@
 (If you are already familiar with the basic concepts of testing, you might want
 to skip to :ref:`the list of assert methods <assert-methods>`.)
 
-The Python unit testing framework, sometimes referred to as "PyUnit," is a
-Python language version of JUnit, by Kent Beck and Erich Gamma. JUnit is, in
-turn, a Java version of Kent's Smalltalk testing framework.  Each is the de
-facto standard unit testing framework for its respective language.
-
-:mod:`unittest` supports test automation, sharing of setup and shutdown code for
-tests, aggregation of tests into collections, and independence of the tests from
-the reporting framework.  The :mod:`unittest` module provides classes that make
-it easy to support these qualities for a set of tests.
-
-To achieve this, :mod:`unittest` supports some important concepts:
+The :mod:`unittest` unit testing framework was originally inspired by JUnit
+and has a similar flavor as major unit testing frameworks in other
+languages.  It supports test automation, sharing of setup and shutdown code
+for tests, aggregation of tests into collections, and independence of the
+tests from the reporting framework.
+
+To achieve this, :mod:`unittest` supports some important concepts in an
+object-oriented way:
 
 test fixture
    A :dfn:`test fixture` represents the preparation needed to perform one or more
@@ -30,7 +27,7 @@
    process.
 
 test case
-   A :dfn:`test case` is the smallest unit of testing.  It checks for a specific
+   A :dfn:`test case` is the individual unit of testing.  It checks for a specific
    response to a particular set of inputs.  :mod:`unittest` provides a base class,
    :class:`TestCase`, which may be used to create new test cases.
 
@@ -44,43 +41,12 @@
    a textual interface, or return a special value to indicate the results of
    executing the tests.
 
-The test case and test fixture concepts are supported through the
-:class:`TestCase` and :class:`FunctionTestCase` classes; the former should be
-used when creating new tests, and the latter can be used when integrating
-existing test code with a :mod:`unittest`\ -driven framework. When building test
-fixtures using :class:`TestCase`, the :meth:`~TestCase.setUp` and
-:meth:`~TestCase.tearDown` methods can be overridden to provide initialization
-and cleanup for the fixture.  With :class:`FunctionTestCase`, existing functions
-can be passed to the constructor for these purposes.  When the test is run, the
-fixture initialization is run first; if it succeeds, the cleanup method is run
-after the test has been executed, regardless of the outcome of the test.  Each
-instance of the :class:`TestCase` will only be used to run a single test method,
-so a new fixture is created for each test.
-
-Test suites are implemented by the :class:`TestSuite` class.  This class allows
-individual tests and test suites to be aggregated; when the suite is executed,
-all tests added directly to the suite and in "child" test suites are run.
-
-A test runner is an object that provides a single method,
-:meth:`~TestRunner.run`, which accepts a :class:`TestCase` or :class:`TestSuite`
-object as a parameter, and returns a result object.  The class
-:class:`TestResult` is provided for use as the result object. :mod:`unittest`
-provides the :class:`TextTestRunner` as an example test runner which reports
-test results on the standard error stream by default.  Alternate runners can be
-implemented for other environments (such as graphical environments) without any
-need to derive from a specific class.
-
 
 .. seealso::
 
    Module :mod:`doctest`
       Another test-support module with a very different flavor.
 
-   `unittest2: A backport of new unittest features for Python 2.4-2.6 <http://pypi.python.org/pypi/unittest2>`_
-      Many new features were added to unittest in Python 2.7, including test
-      discovery. unittest2 allows you to use these features with earlier
-      versions of Python.
-
    `Simple Smalltalk Testing: With Patterns <http://www.XProgramming.com/testfram.htm>`_
       Kent Beck's original paper on testing frameworks using the pattern shared
       by :mod:`unittest`.
@@ -89,7 +55,7 @@
       Third-party unittest frameworks with a lighter-weight syntax for writing
       tests.  For example, ``assert func(10) == 42``.
 
-   `The Python Testing Tools Taxonomy <http://pycheesecake.org/wiki/PythonTestingToolsTaxonomy>`_
+   `The Python Testing Tools Taxonomy <http://wiki.python.org/moin/PythonTestingToolsTaxonomy>`_
       An extensive list of Python testing tools including functional testing
       frameworks and mock object libraries.
 
@@ -173,15 +139,8 @@
 
    OK
 
-Instead of :func:`unittest.main`, there are other ways to run the tests with a
-finer level of control, less terse output, and no requirement to be run from the
-command line.  For example, the last two lines may be replaced with::
-
-   suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
-   unittest.TextTestRunner(verbosity=2).run(suite)
-
-Running the revised script from the interpreter or another script produces the
-following output::
+Passing the ``-v`` option to your test script will instruct :func:`unittest.main`
+to enable a higher level of verbosity, and produce the following output::
 
    test_choice (__main__.TestSequenceFunctions) ... ok
    test_sample (__main__.TestSequenceFunctions) ... ok
@@ -359,45 +318,30 @@
 To make your own test cases you must write subclasses of
 :class:`TestCase` or use :class:`FunctionTestCase`.
 
-An instance of a :class:`TestCase`\ -derived class is an object that can
-completely run a single test method, together with optional set-up and tidy-up
-code.
-
 The testing code of a :class:`TestCase` instance should be entirely self
 contained, such that it can be run either in isolation or in arbitrary
 combination with any number of other test cases.
 
-The simplest :class:`TestCase` subclass will simply override the
-:meth:`~TestCase.runTest` method in order to perform specific testing code::
+The simplest :class:`TestCase` subclass will simply implement a test method
+(i.e. a method whose name starts with ``test``) in order to perform specific
+testing code::
 
    import unittest
 
    class DefaultWidgetSizeTestCase(unittest.TestCase):
-       def runTest(self):
+       def test_default_widget_size(self):
            widget = Widget('The widget')
-           self.assertEqual(widget.size(), (50, 50), 'incorrect default size')
+           self.assertEqual(widget.size(), (50, 50))
 
 Note that in order to test something, we use one of the :meth:`assert\*`
 methods provided by the :class:`TestCase` base class.  If the test fails, an
 exception will be raised, and :mod:`unittest` will identify the test case as a
-:dfn:`failure`.  Any other exceptions will be treated as :dfn:`errors`. This
-helps you identify where the problem is: :dfn:`failures` are caused by incorrect
-results - a 5 where you expected a 6. :dfn:`Errors` are caused by incorrect
-code - e.g., a :exc:`TypeError` caused by an incorrect function call.
-
-The way to run a test case will be described later.  For now, note that to
-construct an instance of such a test case, we call its constructor without
-arguments::
-
-   testCase = DefaultWidgetSizeTestCase()
-
-Now, such test cases can be numerous, and their set-up can be repetitive.  In
-the above case, constructing a :class:`Widget` in each of 100 Widget test case
-subclasses would mean unsightly duplication.
-
-Luckily, we can factor out such set-up code by implementing a method called
-:meth:`~TestCase.setUp`, which the testing framework will automatically call for
-us when we run the test::
+:dfn:`failure`.  Any other exceptions will be treated as :dfn:`errors`.
+
+Tests can be numerous, and their set-up can be repetitive.  Luckily, we
+can factor out set-up code by implementing a method called
+:meth:`~TestCase.setUp`, which the testing framework will automatically
+call for every single test we run::
 
    import unittest
 
@@ -405,23 +349,26 @@
        def setUp(self):
            self.widget = Widget('The widget')
 
-   class DefaultWidgetSizeTestCase(SimpleWidgetTestCase):
-       def runTest(self):
+       def test_default_widget_size(self):
            self.assertEqual(self.widget.size(), (50,50),
                             'incorrect default size')
 
-   class WidgetResizeTestCase(SimpleWidgetTestCase):
-       def runTest(self):
+       def test_widget_resize(self):
            self.widget.resize(100,150)
            self.assertEqual(self.widget.size(), (100,150),
                             'wrong size after resize')
 
+.. note::
+   The order in which the various tests will be run is determined
+   by sorting the test method names with respect to the built-in
+   ordering for strings.
+
 If the :meth:`~TestCase.setUp` method raises an exception while the test is
-running, the framework will consider the test to have suffered an error, and the
-:meth:`~TestCase.runTest` method will not be executed.
+running, the framework will consider the test to have suffered an error, and
+the test method will not be executed.
 
 Similarly, we can provide a :meth:`~TestCase.tearDown` method that tidies up
-after the :meth:`~TestCase.runTest` method has been run::
+after the test method has been run::
 
    import unittest
 
@@ -431,59 +378,20 @@
 
        def tearDown(self):
            self.widget.dispose()
-           self.widget = None
-
-If :meth:`~TestCase.setUp` succeeded, the :meth:`~TestCase.tearDown` method will
-be run whether :meth:`~TestCase.runTest` succeeded or not.
+
+If :meth:`~TestCase.setUp` succeeded, :meth:`~TestCase.tearDown` will be
+run whether the test method succeeded or not.
 
 Such a working environment for the testing code is called a :dfn:`fixture`.
 
-Often, many small test cases will use the same fixture.  In this case, we would
-end up subclassing :class:`SimpleWidgetTestCase` into many small one-method
-classes such as :class:`DefaultWidgetSizeTestCase`.  This is time-consuming and
-discouraging, so in the same vein as JUnit, :mod:`unittest` provides a simpler
-mechanism::
-
-   import unittest
-
-   class WidgetTestCase(unittest.TestCase):
-       def setUp(self):
-           self.widget = Widget('The widget')
-
-       def tearDown(self):
-           self.widget.dispose()
-           self.widget = None
-
-       def test_default_size(self):
-           self.assertEqual(self.widget.size(), (50,50),
-                            'incorrect default size')
-
-       def test_resize(self):
-           self.widget.resize(100,150)
-           self.assertEqual(self.widget.size(), (100,150),
-                            'wrong size after resize')
-
-Here we have not provided a :meth:`~TestCase.runTest` method, but have instead
-provided two different test methods.  Class instances will now each run one of
-the :meth:`test_\*` methods, with ``self.widget`` created and destroyed
-separately for each instance.  When creating an instance we must specify the
-test method it is to run.  We do this by passing the method name in the
-constructor::
-
-   defaultSizeTestCase = WidgetTestCase('test_default_size')
-   resizeTestCase = WidgetTestCase('test_resize')
-
 Test case instances are grouped together according to the features they test.
 :mod:`unittest` provides a mechanism for this: the :dfn:`test suite`,
-represented by :mod:`unittest`'s :class:`TestSuite` class::
-
-   widgetTestSuite = unittest.TestSuite()
-   widgetTestSuite.addTest(WidgetTestCase('test_default_size'))
-   widgetTestSuite.addTest(WidgetTestCase('test_resize'))
-
-For the ease of running tests, as we will see later, it is a good idea to
-provide in each test module a callable object that returns a pre-built test
-suite::
+represented by :mod:`unittest`'s :class:`TestSuite` class.  In most cases,
+calling :func:`unittest.main` will do the right thing and collect all the
+module's test cases for you, and then execute them.
+
+However, should you want to customize the building of your test suite,
+you can do it yourself::
 
    def suite():
        suite = unittest.TestSuite()
@@ -491,37 +399,6 @@
        suite.addTest(WidgetTestCase('test_resize'))
        return suite
 
-or even::
-
-   def suite():
-       tests = ['test_default_size', 'test_resize']
-
-       return unittest.TestSuite(map(WidgetTestCase, tests))
-
-Since it is a common pattern to create a :class:`TestCase` subclass with many
-similarly named test functions, :mod:`unittest` provides a :class:`TestLoader`
-class that can be used to automate the process of creating a test suite and
-populating it with individual tests. For example, ::
-
-   suite = unittest.TestLoader().loadTestsFromTestCase(WidgetTestCase)
-
-will create a test suite that will run ``WidgetTestCase.test_default_size()`` and
-``WidgetTestCase.test_resize``. :class:`TestLoader` uses the ``'test'`` method
-name prefix to identify test methods automatically.
-
-Note that the order in which the various test cases will be run is
-determined by sorting the test function names with respect to the
-built-in ordering for strings.
-
-Often it is desirable to group suites of test cases together, so as to run tests
-for the whole system at once.  This is easy, since :class:`TestSuite` instances
-can be added to a :class:`TestSuite` just as :class:`TestCase` instances can be
-added to a :class:`TestSuite`::
-
-   suite1 = module1.TheTestSuite()
-   suite2 = module2.TheTestSuite()
-   alltests = unittest.TestSuite([suite1, suite2])
-
 You can place the definitions of test cases and test suites in the same modules
 as the code they are to test (such as :file:`widget.py`), but there are several
 advantages to placing the test code in a separate module, such as
@@ -564,23 +441,13 @@
        assert something.name is not None
        # ...
 
-one can create an equivalent test case instance as follows::
-
-   testcase = unittest.FunctionTestCase(testSomething)
-
-If there are additional set-up and tear-down methods that should be called as
-part of the test case's operation, they can also be provided like so::
+one can create an equivalent test case instance as follows, with optional
+set-up and tear-down methods::
 
    testcase = unittest.FunctionTestCase(testSomething,
                                         setUp=makeSomethingDB,
                                         tearDown=deleteSomethingDB)
 
-To make migrating existing test suites easier, :mod:`unittest` supports tests
-raising :exc:`AssertionError` to indicate test failure. However, it is
-recommended that you use the explicit :meth:`TestCase.fail\*` and
-:meth:`TestCase.assert\*` methods instead, as future versions of :mod:`unittest`
-may treat :exc:`AssertionError` differently.
-
 .. note::
 
    Even though :class:`FunctionTestCase` can be used to quickly convert an
@@ -704,32 +571,24 @@
 
 .. class:: TestCase(methodName='runTest')
 
-   Instances of the :class:`TestCase` class represent the smallest testable units
+   Instances of the :class:`TestCase` class represent the logical test units
    in the :mod:`unittest` universe.  This class is intended to be used as a base
    class, with specific tests being implemented by concrete subclasses.  This class
    implements the interface needed by the test runner to allow it to drive the
-   test, and methods that the test code can use to check for and report various
+   tests, and methods that the test code can use to check for and report various
    kinds of failure.
 
-   Each instance of :class:`TestCase` will run a single test method: the method
-   named *methodName*.  If you remember, we had an earlier example that went
-   something like this::
-
-      def suite():
-          suite = unittest.TestSuite()
-          suite.addTest(WidgetTestCase('test_default_size'))
-          suite.addTest(WidgetTestCase('test_resize'))
-          return suite
-
-   Here, we create two instances of :class:`WidgetTestCase`, each of which runs a
-   single test.
+   Each instance of :class:`TestCase` will run a single base method: the method
+   named *methodName*.  However, the standard implementation of the default
+   *methodName*, ``runTest()``, will run every method starting with ``test``
+   as an individual test, and count successes and failures accordingly.
+   Therefore, in most uses of :class:`TestCase`, you will neither change
+   the *methodName* nor reimplement the default ``runTest()`` method.
 
    .. versionchanged:: 3.2
-      :class:`TestCase` can be instantiated successfully without providing a method
-      name. This makes it easier to experiment with :class:`TestCase` from the
-      interactive interpreter.
-
-   *methodName* defaults to :meth:`runTest`.
+      :class:`TestCase` can be instantiated successfully without providing a
+      *methodName*. This makes it easier to experiment with :class:`TestCase`
+      from the interactive interpreter.
 
    :class:`TestCase` instances provide three groups of methods: one group used
    to run the test, another used by the test implementation to check conditions
@@ -738,7 +597,6 @@
 
    Methods in the first group (running the test) are:
 
-
    .. method:: setUp()
 
       Method called to prepare the test fixture.  This is called immediately
@@ -790,10 +648,11 @@
 
    .. method:: run(result=None)
 
-      Run the test, collecting the result into the test result object passed as
-      *result*.  If *result* is omitted or ``None``, a temporary result
-      object is created (by calling the :meth:`defaultTestResult` method) and
-      used. The result object is returned to :meth:`run`'s caller.
+      Run the test, collecting the result into the :class:`TestResult` object
+      passed as *result*.  If *result* is omitted or ``None``, a temporary
+      result object is created (by calling the :meth:`defaultTestResult`
+      method) and used. The result object is returned to :meth:`run`'s
+      caller.
 
       The same effect may be had by simply calling the :class:`TestCase`
       instance.

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list