1 Parallel Testing with nose
2 --------------------------
6 Use of the multiprocess plugin on python 2.5 or earlier requires
7 the multiprocessing_ module, available from PyPI and at
8 http://code.google.com/p/python-multiprocessing/.
12 Using the `nose.plugin.multiprocess` plugin, you can parallelize a
13 test run across a configurable number of worker processes. While this can
14 speed up CPU-bound test runs, it is mainly useful for IO-bound tests
15 that spend most of their time waiting for data to arrive from someplace
16 else and can benefit from parallelization.
18 .. _multiprocessing : http://code.google.com/p/python-multiprocessing/
20 How tests are distributed
21 =========================
23 The ideal case would be to dispatch each test to a worker process separately,
24 and to have enough worker processes that the entire test run takes only as
25 long as the slowest test. This ideal is not attainable in all cases, however,
26 because many test suites depend on context (class, module or package)
29 Some context fixtures are re-entrant -- that is, they can be called many times
30 concurrently. Other context fixtures can be shared among tests running in
31 different processes. Still others must be run once and only once for a given
32 set of tests, and must be in the same process as the tests themselves.
34 The plugin can't know the difference between these types of context fixtures
35 unless you tell it, so the default behavior is to dispatch the entire context
36 suite to a worker as a unit. This way, the fixtures are run once, in the same
37 process as the tests. (That, of course, is how they are run when the plugin
38 is not active: All tests are run in a single process.)
40 Controlling distribution
41 ^^^^^^^^^^^^^^^^^^^^^^^^
43 There are two context-level variables that you can use to control this default
46 If a context's fixtures are re-entrant, set ``_multiprocess_can_split_ = True``
47 in the context, and the plugin will dispatch tests in suites bound to that
48 context as if the context had no fixtures. This means that the fixtures will
49 execute multiple times, typically once per test, and concurrently.
51 For example, a module that contains re-entrant fixtures might look like::
53 _multiprocess_can_split_ = True
58 A class might look like::
61 _multiprocess_can_split_ = True
67 Alternatively, if a context's fixtures may only be run once, or may not run
68 concurrently, but *may* be shared by tests running in different processes
69 -- for instance a package-level fixture that starts an external http server or
70 initializes a shared database -- then set ``_multiprocess_shared_ = True`` in
71 the context. Fixtures for contexts so marked will execute in the primary nose
72 process, and tests in those contexts will be individually dispatched to run in
75 A module with shareable fixtures might look like::
77 _multiprocess_shared_ = True
82 A class might look like::
85 _multiprocess_shared_ = True
91 These options are mutually exclusive: you can't mark a context as both
92 splittable and shareable.
97 Consider three versions of the same test suite. One
98 is marked ``_multiprocess_shared_``, another ``_multiprocess_can_split_``,
99 and the third is unmarked. They all define the same fixtures:
105 called.append('setup')
108 print "teardown called"
109 called.append('teardown')
111 And each has two tests that just test that ``setup()`` has been called
114 When run without the multiprocess plugin, fixtures for the shared,
115 can-split and not-shared test suites execute at the same times, and
120 The run() function in :mod:`nose.plugins.plugintest` reformats test result
121 output to remove timings, which will vary from run to run, and
122 redirects the output to stdout.
124 >>> from nose.plugins.plugintest import run_buffered as run
129 >>> support = os.path.join(os.path.dirname(__file__), 'support')
130 >>> test_not_shared = os.path.join(support, 'test_not_shared.py')
131 >>> test_shared = os.path.join(support, 'test_shared.py')
132 >>> test_can_split = os.path.join(support, 'test_can_split.py')
134 The module with shared fixtures passes.
136 >>> run(argv=['nosetests', '-v', test_shared]) #doctest: +REPORT_NDIFF
138 test_shared.TestMe.test_one ... ok
139 test_shared.test_a ... ok
140 test_shared.test_b ... ok
143 ----------------------------------------------------------------------
148 As does the module with no fixture annotations.
150 >>> run(argv=['nosetests', '-v', test_not_shared]) #doctest: +REPORT_NDIFF
152 test_not_shared.TestMe.test_one ... ok
153 test_not_shared.test_a ... ok
154 test_not_shared.test_b ... ok
157 ----------------------------------------------------------------------
162 And the module that marks its fixtures as re-entrant.
164 >>> run(argv=['nosetests', '-v', test_can_split]) #doctest: +REPORT_NDIFF
166 test_can_split.TestMe.test_one ... ok
167 test_can_split.test_a ... ok
168 test_can_split.test_b ... ok
171 ----------------------------------------------------------------------
176 However, when run with the ``--processes=2`` switch, each test module
179 >>> from nose.plugins.multiprocess import MultiProcess
181 The module marked ``_multiprocess_shared_`` executes correctly, although as with
182 any use of the multiprocess plugin, the order in which the tests execute is
185 First we have to reset all of the test modules.
188 >>> sys.modules['test_not_shared'].called[:] = []
189 >>> sys.modules['test_can_split'].called[:] = []
191 Then we can run the tests again with the multiprocess plugin active.
193 >>> run(argv=['nosetests', '-v', '--processes=2', test_shared],
194 ... plugins=[MultiProcess()]) #doctest: +ELLIPSIS
199 ----------------------------------------------------------------------
204 As does the one not marked -- however in this case, ``--processes=2``
205 will do *nothing at all*: since the tests are in a module with
206 unmarked fixtures, the entire test module will be dispatched to a
207 single runner process.
209 However, the module marked ``_multiprocess_can_split_`` will fail, since
210 the fixtures *are not reentrant*. A module such as this *must not* be
211 marked ``_multiprocess_can_split_``, or tests will fail in one or more
212 runner processes as fixtures are re-executed.
214 We have to reset all of the test modules again.
217 >>> sys.modules['test_not_shared'].called[:] = []
218 >>> sys.modules['test_can_split'].called[:] = []
220 Then we can run again and see the failures.
222 >>> run(argv=['nosetests', '-v', '--processes=2', test_can_split],
223 ... plugins=[MultiProcess()]) #doctest: +ELLIPSIS
228 FAILED (failures=...)
230 Other differences in test running
231 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
233 The main difference between using the multiprocess plugin and not doing so
234 is obviously that tests run concurrently under multiprocess. However, there
235 are a few other differences that may impact your test suite:
237 * More tests may be found
239 Because tests are dispatched to worker processes by name, a worker
240 process may find and run tests in a module that would not be found during a
241 normal test run. For instance, if a non-test module contains a test-like
242 function, that function would be discovered as a test in a worker process
243 if the entire module is dispatched to the worker. This is because worker
244 processes load tests in *directed* mode -- the same way that nose loads
245 tests when you explicitly name a module -- rather than in *discovered* mode,
246 the mode nose uses when looking for tests in a directory.
248 * Out-of-order output
250 Test results are collected by workers and returned to the master process for
251 output. Since different processes may complete their tests at different
252 times, test result output order is not determinate.
254 * Plugin interaction warning
256 The multiprocess plugin does not work well with other plugins that expect to
257 wrap or gain control of the test-running process. Examples from nose's
258 builtin plugins include coverage and profiling: a test run using
259 both multiprocess and either of those is likely to fail in some
260 confusing and spectacular way.
264 This is unlikely to impact you unless you are writing tests for nose itself,
265 but be aware that under python 2.6, the multiprocess plugin is not
266 re-entrant. For example, when running nose with the plugin active, you can't
267 use subprocess to launch another copy of nose that also uses the
268 multiprocess plugin. This is why this test is skipped under python 2.6 when
269 run with the ``--processes`` switch.