#8155: Preserve backward compatibility for test_support.check_warnings(). Add regression tests.

This commit is contained in:
Florent Xicluna 2010-03-18 19:51:47 +00:00
parent f3e9b2a996
commit 735885428d
3 changed files with 87 additions and 65 deletions

View File

@ -90,17 +90,17 @@ The goal for regression testing is to try to break code. This leads to a few
guidelines to be followed:
* The testing suite should exercise all classes, functions, and constants. This
includes not just the external API that is to be presented to the outside world
but also "private" code.
includes not just the external API that is to be presented to the outside
world but also "private" code.
* Whitebox testing (examining the code being tested when the tests are being
written) is preferred. Blackbox testing (testing only the published user
interface) is not complete enough to make sure all boundary and edge cases are
tested.
interface) is not complete enough to make sure all boundary and edge cases
are tested.
* Make sure all possible values are tested including invalid ones. This makes
sure that not only all valid values are acceptable but also that improper values
are handled correctly.
sure that not only all valid values are acceptable but also that improper
values are handled correctly.
* Exhaust as many code paths as possible. Test where branching occurs and thus
tailor input to make sure as many different paths through the code are taken.
@ -120,8 +120,8 @@ guidelines to be followed:
behavior from side-effects of importing a module.
* Try to maximize code reuse. On occasion, tests will vary by something as small
as what type of input is used. Minimize code duplication by subclassing a basic
test class with a class that specifies the input::
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):
@ -155,10 +155,10 @@ Running tests using :mod:`test.regrtest`
suite. 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 be
passed to the script. Specifying a single regression test (:program:`python
regrtest.py` :option:`test_spam.py`) will minimize output and only print whether
the test passed or failed and thus minimize output.
function :func:`test_main` if present. The names of tests to execute may also
be passed to the script. Specifying a single regression test (:program:`python
regrtest.py` :option:`test_spam.py`) will minimize output and only print
whether the test passed or failed and thus minimize output.
Running :mod:`test.regrtest` directly allows what resources are available for
tests to use to be set. You do this by using the :option:`-u` command-line
@ -173,10 +173,10 @@ list of all resources and more command-line options, run :program:`python
regrtest.py` :option:`-h`.
Some other ways to execute the regression tests depend on what platform the
tests are being executed on. On Unix, you can run :program:`make` :option:`test`
at the top-level directory where Python was built. On Windows, executing
:program:`rt.bat` from your :file:`PCBuild` directory will run all regression
tests.
tests are being executed on. On Unix, you can run :program:`make`
:option:`test` at the top-level directory where Python was built. On Windows,
executing :program:`rt.bat` from your :file:`PCBuild` directory will run all
regression tests.
:mod:`test.test_support` --- Utility functions for tests
@ -209,8 +209,9 @@ This module defines the following exceptions:
.. exception:: ResourceDenied
Subclass of :exc:`unittest.SkipTest`. Raised when a resource (such as a network
connection) is not available. Raised by the :func:`requires` function.
Subclass of :exc:`unittest.SkipTest`. Raised when a resource (such as a
network connection) is not available. Raised by the :func:`requires`
function.
The :mod:`test.test_support` module defines the following constants:
@ -256,22 +257,23 @@ The :mod:`test.test_support` module defines the following functions:
.. function:: requires(resource[, msg])
Raise :exc:`ResourceDenied` if *resource* is not available. *msg* is the
argument to :exc:`ResourceDenied` if it is raised. Always returns True if called
by a function whose ``__name__`` is ``'__main__'``. Used when tests are executed
by :mod:`test.regrtest`.
argument to :exc:`ResourceDenied` if it is raised. Always returns
:const:`True` if called by a function whose ``__name__`` is ``'__main__'``.
Used when tests are executed by :mod:`test.regrtest`.
.. function:: findfile(filename)
Return the path to the file named *filename*. If no match is found *filename* is
returned. This does not equal a failure since it could be the path to the file.
Return the path to the file named *filename*. If no match is found
*filename* is returned. This does not equal a failure since it could be the
path to the file.
.. function:: run_unittest(*classes)
Execute :class:`unittest.TestCase` subclasses passed to the function. The
function scans the classes for methods starting with the prefix ``test_`` and
executes the tests individually.
function scans the classes for methods starting with the prefix ``test_``
and executes the tests individually.
It is also legal to pass strings as parameters; these should be keys in
``sys.modules``. Each associated module will be scanned by
@ -284,7 +286,7 @@ The :mod:`test.test_support` module defines the following functions:
This will run all tests defined in the named module.
.. function:: check_warnings(*filters, quiet=False)
.. function:: check_warnings(*filters, quiet=None)
A convenience wrapper for ``warnings.catch_warnings()`` that makes
it easier to test that a warning was correctly raised with a single
@ -292,30 +294,31 @@ The :mod:`test.test_support` module defines the following functions:
``warnings.catch_warnings(record=True)``.
It accepts 2-tuples ``("message regexp", WarningCategory)`` as positional
arguments. When the optional keyword argument ``quiet`` is True, it does
not fail if a filter catches nothing. Without argument, it defaults to::
arguments. If there's some ``*filters`` defined, or if the optional keyword
argument ``quiet`` is :const:`False`, it checks if the warnings are
effective. If some filter did not catch any warning, the test fails. If some
warnings are not caught, the test fails, too. To disable these checks, set
argument ``quiet`` to :const:`True`.
check_warnings(("", Warning), quiet=False)
Without argument, it defaults to::
The main difference is that it verifies the warnings raised. If some filter
did not catch any warning, the test fails. If some warnings are not caught,
the test fails, too. To disable these checks, use argument ``quiet=True``.
check_warnings(("", Warning), quiet=True)
Another significant difference is that on entry to the context manager, a
:class:`WarningRecorder` instance is returned instead of a simple list.
The underlying warnings list is available via the recorder object's
:attr:`warnings` attribute, while the attributes of the last raised
warning are also accessible directly on the object. If no warning has
been raised, then the latter attributes will all be :const:`None`.
Additionally, on entry to the context manager, a :class:`WarningRecorder`
instance is returned. The underlying warnings list is available via the
recorder object's :attr:`warnings` attribute, while the attributes of the
last raised warning are also accessible directly on the object. If no
warning has been raised, then the latter attributes will all be
:const:`None`.
A :meth:`reset` method is also provided on the recorder object. This
method simply clears the warning list.
method simply clears the warnings list.
The context manager may be used like this::
import warnings
with check_warnings():
with check_warnings(quiet=False):
exec('assert(False, "Hey!")')
warnings.warn(UserWarning("Hide me!"))
@ -337,7 +340,6 @@ The :mod:`test.test_support` module defines the following functions:
.. versionadded:: 2.6
.. versionchanged:: 2.7
The test fails when the context manager do not catch any warning.
New optional attributes ``*filters`` and ``quiet``.
@ -348,8 +350,9 @@ The :mod:`test.test_support` module defines the following functions:
If ``sys.py3kwarning == 0``, it checks that no warning is raised.
It accepts 2-tuples ``("message regexp", WarningCategory)`` as positional
arguments. When the optional keyword argument ``quiet`` is True, it does
not fail if a filter catches nothing. Without argument, it defaults to::
arguments. When the optional keyword argument ``quiet`` is :const:`True`, it
does not fail if a filter catches nothing. Without argument, it defaults
to::
check_py3k_warnings(("", DeprecationWarning), quiet=False)
@ -432,11 +435,11 @@ The :mod:`test.test_support` module defines the following classes:
.. versionadded:: 2.6
.. class:: EnvironmentVarGuard()
Class used to temporarily set or unset environment variables. Instances can be
used as a context manager and have a complete dictionary interface for
querying/modifying the underlying ``os.environ``. After exit from the context
manager all changes to environment variables done through this instance will
be rolled back.
Class used to temporarily set or unset environment variables. Instances can
be used as a context manager and have a complete dictionary interface for
querying/modifying the underlying ``os.environ``. After exit from the
context manager all changes to environment variables done through this
instance will be rolled back.
.. versionadded:: 2.6
.. versionchanged:: 2.7
@ -445,7 +448,8 @@ The :mod:`test.test_support` module defines the following classes:
.. method:: EnvironmentVarGuard.set(envvar, value)
Temporarily set the environment variable ``envvar`` to the value of ``value``.
Temporarily set the environment variable ``envvar`` to the value of
``value``.
.. method:: EnvironmentVarGuard.unset(envvar)
@ -459,4 +463,3 @@ The :mod:`test.test_support` module defines the following classes:
:func:`check_warnings` above for more details.
.. versionadded:: 2.6

View File

@ -577,14 +577,19 @@ def check_warnings(*filters, **kwargs):
Optional argument:
- if 'quiet' is True, it does not fail if a filter catches nothing
(default False)
(default True without argument,
default False if some filters are defined)
Without argument, it defaults to:
check_warnings(("", Warning), quiet=False)
check_warnings(("", Warning), quiet=True)
"""
quiet = kwargs.get('quiet')
if not filters:
filters = (("", Warning),)
return _filterwarnings(filters, kwargs.get('quiet'))
# Preserve backward compatibility
if quiet is None:
quiet = True
return _filterwarnings(filters, quiet)
@contextlib.contextmanager

View File

@ -633,19 +633,33 @@ class CatchWarningTests(BaseTest):
def test_check_warnings(self):
# Explicit tests for the test_support convenience wrapper
wmod = self.module
if wmod is sys.modules['warnings']:
with test_support.check_warnings() as w:
self.assertEqual(w.warnings, [])
wmod.simplefilter("always")
wmod.warn("foo")
self.assertEqual(str(w.message), "foo")
wmod.warn("bar")
self.assertEqual(str(w.message), "bar")
self.assertEqual(str(w.warnings[0].message), "foo")
self.assertEqual(str(w.warnings[1].message), "bar")
w.reset()
self.assertEqual(w.warnings, [])
if wmod is not sys.modules['warnings']:
return
with test_support.check_warnings(quiet=False) as w:
self.assertEqual(w.warnings, [])
wmod.simplefilter("always")
wmod.warn("foo")
self.assertEqual(str(w.message), "foo")
wmod.warn("bar")
self.assertEqual(str(w.message), "bar")
self.assertEqual(str(w.warnings[0].message), "foo")
self.assertEqual(str(w.warnings[1].message), "bar")
w.reset()
self.assertEqual(w.warnings, [])
with test_support.check_warnings():
# defaults to quiet=True without argument
pass
with test_support.check_warnings(('foo', UserWarning)):
wmod.warn("foo")
with self.assertRaises(AssertionError):
with test_support.check_warnings(('', RuntimeWarning)):
# defaults to quiet=False with argument
pass
with self.assertRaises(AssertionError):
with test_support.check_warnings(('foo', RuntimeWarning)):
wmod.warn("foo")
class CCatchWarningTests(CatchWarningTests):