~lifeless/testtools/helpers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
======
Manual
======

Introduction
------------

This document provides overview of the features provided by testtools.  Refer
to the API docs (i.e. docstrings) for full details on a particular feature.

Extensions to TestCase
----------------------

TestCase.addCleanup
~~~~~~~~~~~~~~~~~~~

addCleanup is a robust way to arrange for a cleanup function to be called
before tearDown.  This is a powerful and simple alternative to putting cleanup
logic in a try/finally block or tearDown method.  e.g.::

    def test_foo(self):
        foo.lock()
        self.addCleanup(foo.unlock)
        ...


TestCase.skip
~~~~~~~~~~~~~

``skip`` is a simple way to have a test stop running and be reported as a
skipped test, rather than a success/error/failure. This is an alternative to
convoluted logic during test loading, permitting later and more localized
decisions about the appropriateness of running a test. Many reasons exist to
skip a test - for instance when a dependency is missing, or if the test is
expensive and should not be run while on laptop battery power, or if the test
is testing an incomplete feature (this is sometimes called a TODO). Using this
feature when running your test suite with a TestResult object that is missing
the ``addSkip`` method will result in the ``addError`` method being invoked
instead.


New assertion methods
~~~~~~~~~~~~~~~~~~~~~

testtools adds several assertion methods:

 * assertIn
 * assertNotIn
 * assertIs
 * assertIsNot
 * assertIsInstance


Improved assertRaises
~~~~~~~~~~~~~~~~~~~~~

TestCase.assertRaises returns the caught exception.  This is useful for
asserting more things about the exception than just the type::

        error = self.assertRaises(UnauthorisedError, thing.frobnicate)
        self.assertEqual('bob', error.username)
        self.assertEqual('User bob cannot frobnicate', str(error))


Creation methods
~~~~~~~~~~~~~~~~

testtools.TestCase implements creation methods called ``getUniqueString`` and
``getUniqueInteger``.  See pages 419-423 of *xUnit Test Patterns* by Meszaros
for a detailed discussion of creation methods.


Test renaming
~~~~~~~~~~~~~

``testtools.clone_test_with_new_id`` is a function to copy a test case
instance to one with a new name.  This is helpful for implementing test
parameterization.


Extensions to TestResult
------------------------

TestResult.addSkip
~~~~~~~~~~~~~~~~~~

This method is called on result objects when a test skips. The
``testtools.TestResult`` class records skips in its ``skip_reasons`` instance
dict. The can be reported on in much the same way as succesful tests.

TestResult.done
~~~~~~~~~~~~~~~

This method is called on result objects by testtools tests when the attribute
exists. It is used as a hook point to allow clean disconnection of network
resources and similar concerns.

ThreadsafeForwardingResult
~~~~~~~~~~~~~~~~~~~~~~~~~~

A TestResult which forwards activity to another test result, but synchronises
on a semaphore to ensure that all the activity for a single test arrives in a
batch. This allows simple TestResults which do not expect concurrent test
reporting to be fed the activity from multiple test threads, or processes.

Note that when you provide multiple errors for a single test, the target sees
each error as a distinct complete test.

Extensions to TestSuite
-----------------------

ConcurrentTestSuite
~~~~~~~~~~~~~~~~~~~

A TestSuite for parallel testing. This is used in conjuction with a helper that
runs a single suite in some parallel fashion (for instance, forking, handing
off to a subprocess, to a compute cloud, or simple threads).
ConcurrentTestSuite uses the helper to get a number of separate runnable
objects with a run(result), runs them all in threads using the
ThreadsafeForwardingResult to coalesce their activity.