8 This document provides overview of the features provided by testtools. Refer
9 to the API docs (i.e. docstrings) for full details on a particular feature.
11 Extensions to TestCase
12 ----------------------
14 Custom exception handling
15 ~~~~~~~~~~~~~~~~~~~~~~~~~
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
21 >>> self.exception_handlers.insert(-1, (ExceptionClass, handler)).
23 Having done this, if any of setUp, tearDown, or the test method raise
24 ExceptionClass, handler will be called with the test case, test result and the
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.
61 addCleanup is a robust way to arrange for a cleanup function to be called
62 before tearDown. This is a powerful and simple alternative to putting cleanup
63 logic in a try/finally block or tearDown method. e.g.::
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)
76 TestCase.addOnException
77 ~~~~~~~~~~~~~~~~~~~~~~~
79 addOnException adds an exception handler that will be called from the test
80 framework when it detects an exception from your test code. The handler is
81 given the exc_info for the exception, and can use this opportunity to attach
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
106 ``skipTest`` is a simple way to have a test stop running and be reported as a
107 skipped test, rather than a success/error/failure. This is an alternative to
108 convoluted logic during test loading, permitting later and more localized
109 decisions about the appropriateness of running a test. Many reasons exist to
110 skip a test - for instance when a dependency is missing, or if the test is
111 expensive and should not be run while on laptop battery power, or if the test
112 is testing an incomplete feature (this is sometimes called a TODO). Using this
113 feature when running your test suite with a TestResult object that is missing
114 the ``addSkip`` method will result in the ``addError`` method being invoked
115 instead. ``skipTest`` was previously known as ``skip`` but as Python 2.7 adds
116 ``skipTest`` support, the ``skip`` name is now deprecated (but no warning
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
130 New assertion methods
131 ~~~~~~~~~~~~~~~~~~~~~
133 testtools adds several assertion methods:
143 Improved assertRaises
144 ~~~~~~~~~~~~~~~~~~~~~
146 TestCase.assertRaises returns the caught exception. This is useful for
147 asserting more things about the exception than just the type::
149 error = self.assertRaises(UnauthorisedError, thing.frobnicate)
150 self.assertEqual('bob', error.username)
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')))
171 assertThat is a clean way to write complex assertions without tying them to
172 the TestCase inheritance hierarchy (and thus making them easier to reuse).
174 assertThat takes an object to be matched, and a matcher, and fails if the
175 matcher does not match the matchee.
177 See pydoc testtools.Matcher for the protocol that matchers need to implement.
179 testtools includes some matchers in testtools.matchers.
180 python -c 'import testtools.matchers; print testtools.matchers.__all__' will
183 An example using the DocTestMatches matcher which uses doctests example
187 self.assertThat([1,2,3,4], DocTestMatches('[1, 2, 3, 4]'))
193 testtools.TestCase implements creation methods called ``getUniqueString`` and
194 ``getUniqueInteger``. See pages 419-423 of *xUnit Test Patterns* by Meszaros
195 for a detailed discussion of creation methods.
201 ``testtools.clone_test_with_new_id`` is a function to copy a test case
202 instance to one with a new name. This is helpful for implementing test
206 Extensions to TestResult
207 ------------------------
212 This method is called on result objects when a test skips. The
213 ``testtools.TestResult`` class records skips in its ``skip_reasons`` instance
214 dict. The can be reported on in much the same way as succesful tests.
220 This method controls the time used by a TestResult, permitting accurate
221 timing of test results gathered on different machines or in different threads.
222 See pydoc testtools.TestResult.time for more details.
225 ThreadsafeForwardingResult
226 ~~~~~~~~~~~~~~~~~~~~~~~~~~
228 A TestResult which forwards activity to another test result, but synchronises
229 on a semaphore to ensure that all the activity for a single test arrives in a
230 batch. This allows simple TestResults which do not expect concurrent test
231 reporting to be fed the activity from multiple test threads, or processes.
233 Note that when you provide multiple errors for a single test, the target sees
234 each error as a distinct complete test.
240 A TestResult that provides a text UI very similar to the Python standard
241 library UI. Key differences are that its supports the extended outcomes and
242 details API, and is completely encapsulated into the result object, permitting
243 it to be used without a 'TestRunner' object. Not all the Python 2.7 outcomes
244 are displayed (yet). It is also a 'quiet' result with no dots or verbose mode.
245 These limitations will be corrected soon.
251 In testtools.testresult.doubles there are three test doubles that testtools
252 uses for its own testing: Python26TestResult, Python27TestResult,
253 ExtendedTestResult. These TestResult objects implement a single variation of
254 the TestResult API each, and log activity to a list self._events. These are
255 made available for the convenience of people writing their own extensions.
258 startTestRun and stopTestRun
259 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
261 Python 2.7 added hooks 'startTestRun' and 'stopTestRun' which are called
262 before and after the entire test run. 'stopTestRun' is particularly useful for
263 test results that wish to produce summary output.
265 testtools.TestResult provides empty startTestRun and stopTestRun methods, and
266 the default testtools runner will call these methods appropriately.
269 Extensions to TestSuite
270 -----------------------
275 A TestSuite for parallel testing. This is used in conjuction with a helper that
276 runs a single suite in some parallel fashion (for instance, forking, handing
277 off to a subprocess, to a compute cloud, or simple threads).
278 ConcurrentTestSuite uses the helper to get a number of separate runnable
279 objects with a run(result), runs them all in threads using the
280 ThreadsafeForwardingResult to coalesce their activity.
286 testtools provides a convenient way to run a test suite using the testtools
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 ...].
296 testtools includes a backported version of the Python 2.7 glue for using the
297 discover test discovery module. If you either have Python 2.7/3.1 or newer, or
298 install the 'discover' module, then you can invoke discovery::
300 python -m testtools.run discover [path]
302 For more information see the Python 2.7 unittest documentation, or::
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.
325 Lots of the time we would like to conditionally import modules. testtools
326 needs to do this itself, and graciously extends the ability to its users.
331 from twisted.internet import defer
337 defer = try_import('twisted.internet.defer')
343 from StringIO import StringIO
345 from io import StringIO
349 StringIO = try_imports(['StringIO.StringIO', 'io.StringIO'])