Twisted support¶
testtools provides support for testing Twisted code.
Matching Deferreds¶
testtools provides support for making assertions about synchronous
Deferred
s.
A “synchronous” Deferred
is one that does
not need the reactor or any other asynchronous process in order to fire.
Normal application code can’t know when a
Deferred
is going to fire, because that is
generally left up to the reactor. Well-written unit tests provide fake
reactors, or don’t use the reactor at all, so that
Deferred
s fire synchronously.
These matchers allow you to make assertions about when and how
Deferred
s fire, and about what values
they fire with.
See also Testing Deferreds without the reactor and the Deferred howto.
Running tests in the reactor¶
testtools provides support for running asynchronous Twisted tests: tests that
return a Deferred
and run the reactor
until it fires and its callback chain is completed.
Here’s how to use it:
from testtools import TestCase
from testtools.twistedsupport import AsynchronousDeferredRunTest
class MyTwistedTests(TestCase):
run_tests_with = AsynchronousDeferredRunTest
def test_foo(self):
# ...
return d
Note that you do not have to use a special base TestCase
in order to run
Twisted tests, you should just use the regular testtools.TestCase
base class.
You can also run individual tests within a test case class using the Twisted test runner:
class MyTestsSomeOfWhichAreTwisted(TestCase):
def test_normal(self):
pass
@run_test_with(AsynchronousDeferredRunTest)
def test_twisted(self):
# ...
return d
See AsynchronousDeferredRunTest
and
AsynchronousDeferredRunTestForBrokenTwisted
for more information.
Controlling the Twisted logs¶
Users of Twisted Trial will be accustomed to all tests logging to
_trial_temp/test.log
. By default,
AsynchronousDeferredRunTest
will not
do this, but will instead:
- suppress all messages logged during the test run
- attach them as the
twisted-log
detail (see Details) which is shown if the test fails
The first behavior is controlled by the suppress_twisted_logging
parameter
to AsynchronousDeferredRunTest
, which is
set to True
by default. The second is controlled by the
store_twisted_logs
parameter, which is also True
by default.
If store_twisted_logs
is set to False
, you can still get the logs
attached as a detail by using the
CaptureTwistedLogs
fixture. Using the
CaptureTwistedLogs
fixture is equivalent
to setting store_twisted_logs
to True
.
For example:
class DoNotCaptureLogsTests(TestCase):
run_tests_with = partial(AsynchronousDeferredRunTest,
store_twisted_logs=False)
def test_foo(self):
log.msg('logs from this test are not attached')
def test_bar(self):
self.useFixture(CaptureTwistedLogs())
log.msg('logs from this test *are* attached')
Converting Trial tests to testtools tests¶
- Use the
AsynchronousDeferredRunTest
runner - Make sure to upcall to
TestCase.setUp()
andTestCase.tearDown()
- Don’t use
setUpClass
ortearDownClass
- Don’t expect setting
.todo
,.timeout
or.skip
attributes to do anything - Replace
twisted.trial.unittest.SynchronousTestCase.flushLoggedErrors()
withflush_logged_errors()
- Replace
twisted.trial.unittest.TestCase.assertFailure()
withassert_fails_with()
- Trial spins the reactor a couple of times before cleaning it up,
AsynchronousDeferredRunTest
does not. If you rely on this behavior, useAsynchronousDeferredRunTestForBrokenTwisted
.