[Python-Dev] PEP: Consolidating names in the `unittest` module

Collin Winter collinw at gmail.com
Wed Jul 16 02:20:30 CEST 2008


On Tue, Jul 15, 2008 at 6:58 AM, Ben Finney <ben+python at benfinney.id.au> wrote:
> Significant updates include removing all reference to the
> (already-resolved) new-style class issue, adding footnotes and
> references, and a Rationale summary of discussion on both sides of the
> divide for 'assert*' versus 'fail*' names.
>
>
> :PEP:               XXX
> :Title:             Consolidating names in the `unittest` module
> :Version:           0.2
> :Last-Modified:     2008-07-15
> :Author:            Ben Finney <ben+python at benfinney.id.au>
> :Status:            Draft
> :Type:              Standards Track
> :Content-Type:      test/x-rst
> :Created:           2008-07-14
> :Python-Version:    2.7, 3.1
> :Post-History:
>
>
> ..  contents::
>
>
> Abstract
> ========
>
> This PEP proposes to consolidate the names that constitute the API of
> the standard library `unittest` module, with the goal of removing
> redundant names, and conforming with PEP 8.
>
>
> Motivation
> ==========
>
> The normal use case for the `unittest` module is to subclass its
> classes, overriding and re-using its functios and methods. This draws
> constant attention to the fact that the existing implementation fails
> several current Python standards:
>
> * It does not conform to PEP 8 [#PEP-8]_, requiring users to write
>  their own non-PEP-8 conformant names when overriding methods, and
>  encouraging extensions to further depart from PEP 8.
>
> * It has many synonyms in its API, which goes against the Zen of
>  Python [#PEP-20]_ (specifically, that "there should be one, and
>  preferably only one, obvious way to do it").
>
>
> Specification
> =============
>
> Remove obsolete names
> ---------------------
>
> The following module attributes are not documented as part of the API
> and are marked as obsolete in the implementation. They will be
> removed.
>
> * ``_makeLoader``
> * ``getTestCaseNames``
> * ``makeSuite``
> * ``findTestCases``
>
> Remove redundant names
> ----------------------
>
> The following attribute names exist only as synonyms for other names.
> They are to be removed, leaving only one name for each attribute in
> the API.
>
> ``TestCase`` attributes
> ~~~~~~~~~~~~~~~~~~~~~~~
>
> * ``assertEqual``
> * ``assertEquals``
> * ``assertNotEqual``
> * ``assertNotEquals``
> * ``assertAlmostEqual``
> * ``assertAlmostEquals``
> * ``assertNotAlmostEqual``
> * ``assertNotAlmostEquals``
> * ``assertRaises``
> * ``assert_``
> * ``assertTrue``
> * ``assertFalse``
>
> Conform API with PEP 8
> ----------------------
>
> The following names are to be introduced, each replacing an existing
> name, to make all names in the module conform with PEP 8 [#PEP-8]_.
> Each name is shown with the existing name that it replaces.
>
> Where function parameters are to be renamed also, they are shown.
> Where function parameters are not to be renamed, they are elided with
> the ellipse ("…") symbol.
>
> Module attributes
> ~~~~~~~~~~~~~~~~~
>
> ``default_test_loader``
>  Replaces ``defaultTestLoader``
>
> ``TestResult`` attributes
> ~~~~~~~~~~~~~~~~~~~~~~~~~
>
> ``add_error(…)``
>  Replaces ``addError(…)``
>
> ``add_result(…)``
>  Replaces ``addResult(…)``
>
> ``add_success(…)``
>  Replaces ``addSuccess(…)``
>
> ``should_stop``
>  Replaces ``shouldStop``
>
> ``start_test(…)``
>  Replaces ``startTest(…)``
>
> ``stop_test(…)``
>  Replaces ``stopTest(…)``
>
> ``tests_run``
>  Replaces ``testsRun``
>
> ``was_successful(…)``
>  Replaces ``wasSuccessful(…)``
>
> ``TestCase`` attributes
> ~~~~~~~~~~~~~~~~~~~~~~~
>
> ``__init__(self, method_name='run_test')``
>  Replaces ``__init__(self, methodName='runTest')``
>
> ``_test_method_doc``
>  Replaces ``_testMethodDoc``
>
> ``_test_method_name``
>  Replaces ``_testMethodName``
>
> ``failure_exception``
>  Replaces ``failureException``
>
> ``count_test_cases(…)``
>  Replaces ``countTestCases(…)``
>
> ``default_test_result(…)``
>  Replaces ``defaultTestResult(…)``
>
> ``fail_if(…)``
>  Replaces ``failIf(…)``
>
> ``fail_if_almost_equal(…)``
>  Replaces ``failIfAlmostEqual(…)``
>
> ``fail_if_equal(…)``
>  Replaces ``failIfEqual(…)``
>
> ``fail_unless(…)``
>  Replaces ``failUnless(…)``
>
> ``fail_unless_almost_equal(…)``
>  Replaces ``failUnlessAlmostEqual(…)``
>
> ``fail_unless_equal(…)``
>  Replaces ``failUnlessEqual(…)``
>
> ``fail_unless_raises(exc_class, callable_obj, *args, **kwargs)``
>  Replaces ``failUnlessRaises(excClass, callableObj, *args, **kwargs)``
>
> ``run_test(…)``
>  Replaces ``runTest(…)``
>
> ``set_up(…)``
>  Replaces ``setUp(…)``
>
> ``short_description(…)``
>  Replaces ``shortDescription(…)``
>
> ``tear_down(…)``
>  Replaces ``tearDown(…)``
>
> ``FunctionTestCase`` attributes
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> ``__init__(self, test_func, set_up, tear_down, description)``
>  Replaces ``__init__(self, testFunc, setUp, tearDown, description)``
>
> ``run_test(…)``
>  Replaces ``runTest(…)``
>
> ``set_up(…)``
>  Replaces ``setUp(…)``
>
> ``short_description(…)``
>  Replaces ``shortDescription(…)``
>
> ``tear_down(…)``
>  Replaces ``tearDown(…)``
>
> ``TestSuite`` attributes
> ~~~~~~~~~~~~~~~~~~~~~~~~
>
> ``add_test(…)``
>  Replaces ``addTest(…)``
>
> ``add_tests(…)``
>  Replaces ``addTests(…)``
>
> ``count_test_cases(…)``
>  Replaces ``countTestCases(…)``
>
> ``TestLoader`` attributes
> ~~~~~~~~~~~~~~~~~~~~~~~~~
>
> ``sort_test_methods_using``
>  Replaces ``sortTestMethodsUsing``
>
> ``suite_class``
>  Replaces ``suiteClass``
>
> ``test_method_prefix``
>  Replaces ``testMethodPrefix``
>
> ``get_test_case_names(self, test_case_class)``
>  Replaces ``getTestCaseNames(self, testCaseClass)``
>
> ``load_tests_from_module(…)``
>  Replaces ``loadTestsFromModule(…)``
>
> ``load_tests_from_name(…)``
>  Replaces ``loadTestsFromName(…)``
>
> ``load_tests_from_names(…)``
>  Replaces ``loadTestsFromNames(…)``
>
> ``load_tests_from_test_case(self, test_case_class)``
>  Replaces ``loadTestsFromTestCase(self, testCaseClass)``
>
> ``_TextTestResult`` attributes
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> ``show_all``
>  Replaces ``showAll``
>
> ``add_error(…)``
>  Replaces ``addError(…)``
>
> ``add_failure(…)``
>  Replaces ``addFailure(…)``
>
> ``add_success(…)``
>  Replaces ``addSuccess(…)``
>
> ``get_description(…)``
>  Replaces ``getDescription(…)``
>
> ``print_error_list(…)``
>  Replaces ``printErrorList(…)``
>
> ``print_errors(…)``
>  Replaces ``printErrors(…)``
>
> ``start_test(…)``
>  Replaces ``startTest(…)``
>
> ``TextTestRunner`` attributes
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> ``_make_result(…)``
>  Replaces ``_makeResult(…)``
>
> ``TestProgram`` attributes
> ~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> ``__init__(self, module, default_test, argv, test_runner, test_loader)``
>  Replaces ``__init__(self, module, defaultTest, argv, testRunner, testLoader)``
>
> ``create_tests(…)``
>  Replaces ``createTests(…)``
>
> ``parse_args(…)``
>  Replaces ``parseArgs(…)``
>
> ``run_tests(…)``
>  Replaces ``runTests(…)``
>
> ``usage_exit(…)``
>  Replaces ``usageExit(…)``
>
>
> Rationale
> =========
>
> Redundant names
> ---------------
>
> The current API, with two or in some cases three different names
> referencing exactly the same function, leads to an overbroad and
> redundant API that violates PEP 20 [#PEP-20]_ ("there should be one,
> and preferably only one, obvious way to do it").
>
> Removal of ``assert*`` names
> ----------------------------
>
> While there is consensus support to `remove redundant names`_ for the
> ``TestCase`` test methods, the issue of which set of names should be
> retained is controversial.
>
> Arguments in favour of retaining only the ``assert*`` names:
>
> * BDFL preference: The BDFL has stated [#vanrossum-1]_ a preference
>  for the ``assert*`` names.
>
> * Precedent: The Python standard library currently uses the
>  ``assert*`` names by a roughly 8:1 majority over the ``fail*``
>  names. (Counting unit tests in the py3k tree at 2008-07-15
>  [#pitrou-1]_.)
>
>  An ad-hoc sampling of other projects that use `unittest` also
>  demonstrates strong preference for use of the ``assert*`` names
>  [#bennetts-1]_.
>
> * Positive admonition: The ``assert*`` names state the intent of how
>  the code under test *should* behave, while the ``fail*`` names are
>  phrased in terms of how the code *should not* behave.
>
> Arguments in favour of retaining only the ``fail*`` names:
>
> * Explicit is better than implicit: The ``fail*`` names state *what
>  the function will do* explicitly: fail the test. With the
>  ``assert*`` names, the action to be taken is only implicit.
>
> * Avoid false implication: The test methods do not have any necessary
>  connection with the built-in ``assert`` statement. Even the
>  exception raised, while it defaults to ``AssertionException``, is
>  explicitly customisable via the documented ``failure_exception``
>  attribute. Choosing the ``fail*`` names avoids the false association
>  with either of these.
>
>  This is exacerbated by the plain-boolean test using a name of
>  ``assert_`` (with a trailing underscore) to avoid a name collision
>  with the built-in ``assert`` statement. The corresponding
>  ``fail_if`` name has no such issue.
>
> PEP 8 names
> -----------
>
> Although `unittest` (and its predecessor `PyUnit`) are intended to be
> familiar to users of other xUnit interfaces, there is no attempt at
> direct API compatibility since the only code that Python's `unittest`
> interfaces with is other Python code. The module is in the standard
> library and its names should all conform with PEP 8 [#PEP-8]_.
>
>
> Backwards Compatibility
> =======================
>
> The names to be obsoleted should be deprecated and removed according
> to the schedule for modules in PEP 4 [#PEP-4]_.
>
> While deprecated, use of the deprecated attributes should raise a
> ``DeprecationWarning``, with a message stating which replacement name
> should be used.

Is any provision being made for a 2to3 fixer/otherwise-automated
transition for the changes you propose here?

Collin Winter


More information about the Python-Dev mailing list