The :mod:`treq.testing` module provides some tools for testing both HTTP clients which use the treq API and implementations of the Twisted Web resource model.
The :class:`~treq.testing.StubTreq` class implements the :mod:`treq` module interface (:func:`treq.get()`, :func:`treq.post()`, etc.) but runs all I/O via a :class:`~twisted.internet.testing.MemoryReactor`. It wraps a :class:`twisted.web.resource.IResource` provider which handles each request.
You can wrap a pre-existing IResource provider, or write your own. For example, the :class:`twisted.web.resource.ErrorPage` resource can produce an arbitrary HTTP status code. :class:`twisted.web.static.File` can serve files or directories. And you can easily achieve custom responses by writing trivial resources yourself:
.. literalinclude:: examples/iresource.py :linenos: :pyobject: JsonResource
However, those resources don't assert anything about the request.
The :class:`~treq.testing.RequestSequence` and :class:`~treq.testing.StringStubbingResource` classes make it easy to construct a resource which encodes the expected request and response pairs.
Do note that most parameters to these functions must be bytes—it's safest to use the b''
string syntax, which works on both Python 2 and 3.
For example:
.. literalinclude:: examples/testing_seq.py :linenos:
This may be run with trial testing_seq.py
.
Download: :download:`testing_seq.py <examples/testing_seq.py>`.
If you don't care about certain parts of the request, you can pass :data:`unittest.mock.ANY`, which compares equal to anything. This sequence matches a single GET request with any parameters or headers:
from unittest.mock import ANY
RequestSequence([
((b'get', ANY, ANY, b''), (200, {}, b'ok'))
])
If you care about headers, use :class:`~treq.testing.HasHeaders` to make assertions about the headers present in the request.
It compares equal to a superset of the headers specified, which helps make your test robust to changes in treq or Agent.
Right now treq adds the Accept-Encoding: gzip
header, but as support for additional compression methods is added, this may change.
Since :class:`~treq.testing.StubTreq` wraps any resource, you can use it to test your server-side code as well.
This is superior to calling your resource's methods directly or passing mock objects, since it uses a real :class:`~twisted.web.client.Agent` to generate the request and a real :class:`~twisted.web.server.Site` to process the response.
Thus, the request
object your code interacts with is a real :class:`twisted.web.server.Request` and behaves the same as it would in production.
Note that if your resource returns :data:`~twisted.web.server.NOT_DONE_YET` you must keep a reference to the :class:`~treq.testing.RequestTraversalAgent` and call its :meth:`~treq.testing.RequestTraversalAgent.flush()` method to spin the memory reactor once the server writes additional data before the client will receive it.