[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