11
11
Extensions to TestCase
12
12
----------------------
14
Controlling test execution
15
~~~~~~~~~~~~~~~~~~~~~~~~~~
14
Custom exception handling
15
~~~~~~~~~~~~~~~~~~~~~~~~~
17
Testtools supports two ways to control how tests are executed. The simplest
18
is to add a new exception to self.exception_handlers::
17
testtools provides a way to control how test exceptions are handled. To do
18
this, add a new exception to self.exception_handlers on a TestCase. For
20
21
>>> self.exception_handlers.insert(-1, (ExceptionClass, handler)).
23
24
ExceptionClass, handler will be called with the test case, test result and the
26
Secondly, by overriding __init__ to pass in runTest=RunTestFactory the whole
27
execution of the test can be altered. The default is testtools.runtest.RunTest
28
and calls case._run_setup, case._run_test_method and finally
29
case._run_teardown. Other methods to control what RunTest is used may be
27
Controlling test execution
28
~~~~~~~~~~~~~~~~~~~~~~~~~~
30
If you want to control more than just how exceptions are raised, you can
31
provide a custom `RunTest` to a TestCase. The `RunTest` object can change
32
everything about how the test executes.
34
To work with `testtools.TestCase`, a `RunTest` must have a factory that takes
35
a test and an optional list of exception handlers. Instances returned by the
36
factory must have a `run()` method that takes an optional `TestResult` object.
38
The default is `testtools.runtest.RunTest` and calls 'setUp', the test method
39
and 'tearDown' in the normal, vanilla way that Python's standard unittest
42
To specify a `RunTest` for all the tests in a `TestCase` class, do something
45
class SomeTests(TestCase):
46
run_tests_with = CustomRunTestFactory
48
To specify a `RunTest` for a specific test in a `TestCase` class, do::
50
class SomeTests(TestCase):
51
@run_test_with(CustomRunTestFactory, extra_arg=42, foo='whatever')
52
def test_something(self):
55
In addition, either of these can be overridden by passing a factory in to the
56
`TestCase` constructor with the optional 'runTest' argument.
33
58
TestCase.addCleanup
34
59
~~~~~~~~~~~~~~~~~~~
42
67
self.addCleanup(foo.unlock)
70
Cleanups can also report multiple errors, if appropriate by wrapping them in
71
a testtools.MultipleExceptions object::
73
raise MultipleExceptions(exc_info1, exc_info2)
46
76
TestCase.addOnException
47
77
~~~~~~~~~~~~~~~~~~~~~~~
52
82
more data (via the addDetails API) and potentially other uses.
88
``patch`` is a convenient way to monkey-patch a Python object for the duration
89
of your test. It's especially useful for testing legacy code. e.g.::
92
my_stream = StringIO()
93
self.patch(sys, 'stderr', my_stream)
94
run_some_code_that_prints_to_stderr()
95
self.assertEqual('', my_stream.getvalue())
97
The call to ``patch`` above masks sys.stderr with 'my_stream' so that anything
98
printed to stderr will be captured in a StringIO variable that can be actually
99
tested. Once the test is done, the real sys.stderr is restored to its rightful
68
116
``skipTest`` support, the ``skip`` name is now deprecated (but no warning
69
117
is emitted yet - some time in the future we may do so).
122
``useFixture(fixture)`` calls setUp on the fixture, schedules a cleanup to
123
clean it up, and schedules a cleanup to attach all details held by the
124
fixture to the details dict of the test case. The fixture object should meet
125
the ``fixtures.Fixture`` protocol (version 0.3.4 or newer). This is useful
126
for moving code out of setUp and tearDown methods and into composable side
72
130
New assertion methods
73
131
~~~~~~~~~~~~~~~~~~~~~
92
150
self.assertEqual('bob', error.username)
93
151
self.assertEqual('User bob cannot frobnicate', str(error))
153
Note that this is incompatible with the assertRaises in unittest2/Python2.7.
154
While we have no immediate plans to change to be compatible consider using the
155
new assertThat facility instead::
158
lambda: thing.frobnicate('foo', 'bar'),
159
Raises(MatchesException(UnauthorisedError('bob')))
161
There is also a convenience function to handle this common case::
164
lambda: thing.frobnicate('foo', 'bar'),
165
raises(UnauthorisedError('bob')))
96
168
TestCase.assertThat
97
169
~~~~~~~~~~~~~~~~~~~
214
Testtools provides a convenient way to run a test suite using the testtools
286
testtools provides a convenient way to run a test suite using the testtools
215
287
result object: python -m testtools.run testspec [testspec...].
289
To run tests with Python 2.4, you'll have to do something like:
290
python2.4 /path/to/testtools/run.py testspec [testspec ...].
220
Testtools includes a backported version of the Python 2.7 glue for using the
296
testtools includes a backported version of the Python 2.7 glue for using the
221
297
discover test discovery module. If you either have Python 2.7/3.1 or newer, or
222
298
install the 'discover' module, then you can invoke discovery::
226
302
For more information see the Python 2.7 unittest documentation, or::
228
304
python -m testtools.run --help
310
Support for running Twisted tests is very experimental right now. You
311
shouldn't really do it. However, if you are going to, here are some tips for
312
converting your Trial tests into testtools tests.
314
* Use the AsynchronousDeferredRunTest runner
315
* Make sure to upcall to setUp and tearDown
316
* Don't use setUpClass or tearDownClass
317
* Don't expect setting .todo, .timeout or .skip attributes to do anything
318
* flushLoggedErrors is not there for you. Sorry.
319
* assertFailure is not there for you. Even more sorry.