# Twisted support

testtools provides support for testing Twisted code. Install the `testtools[twisted]` extra to use this.

## 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.

testtools.twistedsupport.succeeded(matcher)

  Match a Deferred that has fired successfully.

  For example:

      fires_with_the_answer = succeeded(Equals(42))
      deferred = defer.succeed(42)
      assert_that(deferred, fires_with_the_answer)

  This assertion will pass. However, if `deferred` had fired with a different value, or had failed, or had not fired at all, then it would fail.

  Use this instead of `twisted.trial.unittest.SynchronousTestCase.successResultOf()`.

  Parameters:

    matcher – A matcher to match against the result of a `Deferred`.

  Returns:

    A matcher that can be applied to a synchronous `Deferred`.

testtools.twistedsupport.failed(matcher)

  Match a Deferred that has failed.

  For example:

      error = RuntimeError('foo')
      fails_at_runtime = failed(
          AfterPreprocessing(lambda f: f.value, Equals(error)))
      deferred = defer.fail(error)
      assert_that(deferred, fails_at_runtime)

  This assertion will pass. However, if `deferred` had fired successfully, had failed with a different error, or had not fired at all, then it would fail.

  Use this instead of `twisted.trial.unittest.SynchronousTestCase.failureResultOf()`.

  Parameters:

    matcher – A matcher to match against the result of a failing `Deferred`.

  Returns:

    A matcher that can be applied to a synchronous `Deferred`.

testtools.twistedsupport.has_no_result()

  Match a Deferred that has not yet fired.

  For example, this will pass:

      assert_that(defer.Deferred(), has_no_result())

  But this will fail:

      >>> assert_that(defer.succeed(None), has_no_result())
      Traceback (most recent call last):
        ...
        File "testtools/assertions.py", line 22, in assert_that
          raise MismatchError(matchee, matcher, mismatch, verbose)
      testtools.matchers._impl.MismatchError: No result expected on <Deferred at ...
          current result: None>, found None instead

  As will this:

      >>> assert_that(defer.fail(RuntimeError('foo')), has_no_result())
      Traceback (most recent call last):
        ...
        File "testtools/assertions.py", line 22, in assert_that
          raise MismatchError(matchee, matcher, mismatch, verbose)
      testtools.matchers._impl.MismatchError: No result expected on <Deferred at ...
          current result: <twisted.python.failure.Failure
          <type 'exceptions.RuntimeError'>>>, found
          <twisted.python.failure.Failure <type 'exceptions.RuntimeError'>> instead

## 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:

> 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 `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()` and `TestCase.tearDown()`

- Don’t use `setUpClass` or `tearDownClass`

- Don’t expect setting `.todo`, `.timeout` or `.skip` attributes to do anything

- Replace `twisted.trial.unittest.SynchronousTestCase.flushLoggedErrors()` with `flush_logged_errors()`

- Replace `twisted.trial.unittest.TestCase.assertFailure()` with `assert_fails_with()`

- Trial spins the reactor a couple of times before cleaning it up, `AsynchronousDeferredRunTest` does not. If you rely on this behavior, use `AsynchronousDeferredRunTestForBrokenTwisted`.