1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
.. _twisted-support:
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
:py:class:`~twisted.internet.defer.Deferred`\s.
A "synchronous" :py:class:`~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:class:`~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:class:`~twisted.internet.defer.Deferred`\s fire synchronously.
These matchers allow you to make assertions about when and how
:py:class:`~twisted.internet.defer.Deferred`\s fire, and about what values
they fire with.
See also `Testing Deferreds without the reactor`_ and the `Deferred howto`_.
.. autofunction:: testtools.twistedsupport.succeeded
:noindex:
.. autofunction:: testtools.twistedsupport.failed
:noindex:
.. autofunction:: testtools.twistedsupport.has_no_result
:noindex:
Running tests in the reactor
----------------------------
testtools provides support for running asynchronous Twisted tests: tests that
return a :py:class:`~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 :py:class:`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 :py:class:`~testtools.twistedsupport.AsynchronousDeferredRunTest` and
:py:class:`~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:class:`~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 :ref:`details`) which is
shown if the test fails
The first behavior is controlled by the ``suppress_twisted_logging`` parameter
to :py:class:`~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:class:`~testtools.twistedsupport.CaptureTwistedLogs` fixture. Using the
:py:class:`~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:class:`~testtools.twistedsupport.AsynchronousDeferredRunTest` runner
* Make sure to upcall to :py:meth:`.TestCase.setUp` and
:py:meth:`.TestCase.tearDown`
* Don't use ``setUpClass`` or ``tearDownClass``
* Don't expect setting ``.todo``, ``.timeout`` or ``.skip`` attributes to do
anything
* Replace
:py:meth:`twisted.trial.unittest.SynchronousTestCase.flushLoggedErrors`
with
:py:func:`~testtools.twistedsupport.flush_logged_errors`
* Replace :py:meth:`twisted.trial.unittest.TestCase.assertFailure` with
:py:func:`~testtools.twistedsupport.assert_fails_with`
* Trial spins the reactor a couple of times before cleaning it up,
:py:class:`~testtools.twistedsupport.AsynchronousDeferredRunTest` does not. If
you rely on this behavior, use
:py:class:`~testtools.twistedsupport.AsynchronousDeferredRunTestForBrokenTwisted`.
.. _Deferred Howto: http://twistedmatrix.com/documents/current/core/howto/defer.html
.. _Testing Deferreds without the reactor:
http://twistedmatrix.com/documents/current/core/howto/trial.html#testing-deferreds-without-the-reactor
|