Files
deb-python-testtools/doc/twisted-support.rst
Jonathan Lange 302751ef67 Options for logging in AsynchronousDeferredRunTest
* Exposes `CaptureTwistedLogs`, a fixture responsible for adding Twisted
  logs as a detail
* Adds `suppress_twisted_logging` and `store_twisted_logs` parameters to
  `AsynchronousDeferredRunTest`
2016-02-03 12:14:47 +00:00

4.9 KiB

Twisted support

testtools provides support for testing Twisted code.

Matching Deferreds

testtools provides support for making assertions about synchronous :py~twisted.internet.defer.Deferreds.

A "synchronous" :py~twisted.internet.defer.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 :py~twisted.internet.defer.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 :py~twisted.internet.defer.Deferreds fire synchronously.

These matchers allow you to make assertions about when and how :py~twisted.internet.defer.Deferreds fire, and about what values they fire with.

See also Testing Deferreds without the reactor and the Deferred howto.

testtools.twistedsupport.succeeded

testtools.twistedsupport.failed

testtools.twistedsupport.has_no_result

Running tests in the reactor

testtools provides support for running asynchronous Twisted tests: tests that return a :py~twisted.internet.defer.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 :pytesttools.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 :py~testtools.twistedsupport.AsynchronousDeferredRunTest and :py~testtools.twistedsupport.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, :py~testtools.twistedsupport.AsynchronousDeferredRunTest will not do this, but will instead:

  1. suppress all messages logged during the test run
  2. 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 :py~testtools.twistedsupport.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 :py~testtools.twistedsupport.CaptureTwistedLogs fixture. Using the :py~testtools.twistedsupport.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 :py~testtools.twistedsupport.AsynchronousDeferredRunTest runner
  • Make sure to upcall to :py.TestCase.setUp and :py.TestCase.tearDown
  • Don't use setUpClass or tearDownClass
  • Don't expect setting .todo, .timeout or .skip attributes to do anything
  • Replace :pytwisted.trial.unittest.SynchronousTestCase.flushLoggedErrors with :py~testtools.twistedsupport.flush_logged_errors
  • Replace :pytwisted.trial.unittest.TestCase.assertFailure with :py~testtools.twistedsupport.assert_fails_with
  • Trial spins the reactor a couple of times before cleaning it up, :py~testtools.twistedsupport.AsynchronousDeferredRunTest does not. If you rely on this behavior, use :py~testtools.twistedsupport.AsynchronousDeferredRunTestForBrokenTwisted.