Twisted support¶
testtools provides support for testing Twisted code.
Matching Deferreds¶
testtools provides support for making assertions about synchronous
Deferreds.
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
Deferreds fire synchronously.
These matchers allow you to make assertions about when and how
Deferreds 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-logdetail (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
AsynchronousDeferredRunTestrunner - Make sure to upcall to
TestCase.setUp()andTestCase.tearDown() - Don’t use
setUpClassortearDownClass - Don’t expect setting
.todo,.timeoutor.skipattributes 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,
AsynchronousDeferredRunTestdoes not. If you rely on this behavior, useAsynchronousDeferredRunTestForBrokenTwisted.