pytest-twisted
pytest-twisted is a plugin for the pytest testing framework that facilitates testing code built with the Twisted asynchronous networking framework. It allows pytest test functions to return Twisted Deferred objects, ensuring that tests wait for asynchronous operations to complete, and manages the Twisted reactor lifecycle within the test suite. The library is actively maintained, with its current version being 1.14.3.
Common errors
-
RuntimeError: This event loop is already running
cause Attempting to run `twisted.trial.unittest.TestCase` tests alongside standard `pytest-twisted` tests, particularly when the `asyncio` reactor is enabled, leading to conflicting event loop management.fixIsolate `twisted.trial` tests from `pytest-twisted` tests or avoid using `asyncio` reactor when running mixed tests. `pytest-twisted` is optimized for `pytest`-style tests returning `Deferreds`. -
NotImplementedError (typically on Windows with Python 3.8+ and asyncio reactor)
cause The default `asyncio` proactor event loop on Windows in Python 3.8+ is not fully compatible with Twisted's `asyncio` reactor implementation.fixForce the use of the `asyncio.WindowsSelectorEventLoopPolicy` in a `conftest.py` file to ensure the selector loop is used. Refer to the 'Gotcha' warning for a code example. -
Tests hang indefinitely without error output.
cause An unhandled exception within a `Deferred` chain (e.g., a missing `errback` handler) can prevent the Deferred from firing, causing `pytest-twisted` to wait indefinitely.fixEnsure all `Deferred` objects have appropriate `addErrback` handlers to catch and log exceptions. Use Twisted's debugging tools (like `Deferred.debug(True)`) during development to identify unhandled errors. -
DeprecationWarning: returnValue was deprecated in Twisted 24.7.0; please use standard return statement instead.
cause Using `twisted.internet.defer.returnValue()` within `inlineCallbacks` generators instead of a plain `return` statement, which is no longer recommended in recent Twisted versions.fixReplace all instances of `returnValue(value)` with `return value` in `inlineCallbacks`-decorated functions.
Warnings
- deprecated `twisted.internet.defer.returnValue` is deprecated since Twisted 24.7.0. Users should migrate to using standard Python `return` statements in `inlineCallbacks` generators.
- gotcha On Windows with Python 3.8+ and the `asyncio` reactor, you might encounter a `NotImplementedError` due to asyncio's default proactor loop not fully supporting Twisted's `asyncio` integration.
- gotcha Directly using `twisted.internet.defer.inlineCallbacks` or `twisted.internet.defer.ensureDeferred` as decorators for pytest test functions that rely on fixtures can lead to unexpected behavior or failures.
- gotcha Mixing `pytest` tests with `twisted.trial.unittest.TestCase` in the same test run, especially when using the `--reactor=asyncio` option, can result in a `RuntimeError: This event loop is already running`.
- breaking Older versions of `pytest-twisted` might have compatibility issues with newer `pytest` releases (e.g., `pytest` 8.2.0+).
- breaking The behavior of `pytest.skip()` in `twisted.trial` unittests changed with Twisted 25.5.0, potentially causing unhandled exceptions when `pytest-twisted` is used.
Install
-
pip install pytest-twisted
Imports
- inlineCallbacks
from twisted.internet.defer import inlineCallbacks
from pytest_twisted import inlineCallbacks
- ensureDeferred
from twisted.internet.defer import ensureDeferred
from pytest_twisted import ensureDeferred
- pytest_twisted
import pytest_twisted
Quickstart
import pytest
from twisted.internet.defer import Deferred
from pytest_twisted import inlineCallbacks
@inlineCallbacks
def test_deferred_returns_value():
d = Deferred()
d.callback('hello')
result = yield d
assert result == 'hello'
@pytest.mark.reactor_default # Or specify --reactor=asyncio in pytest command
@inlineCallbacks
def test_reactor_is_running():
from twisted.internet import reactor
assert reactor.running
# To run this, save as test_example.py and run: pytest test_example.py