py.test plugin for testing Python 3.5+ Tornado code
A simple pytest plugin that provides some helpful fixtures for testing Tornado (version 5.0 or newer) apps and easy handling of plain (undecoratored) native coroutine tests (Python 3.5+).
Why another Tornado pytest plugin when the excellent pytest-tornado already exists? The main reason is that I didn’t want to have to decorate every test coroutine with @pytest.mark.gen_test. This plugin doesn’t have anything like gen_test. Defining a test with async def and a name that begins with test_ is all that is required.
Install using pip, which must be run with Python 3.5+:
pip install pytest-tornasync
Define an app fixture:
import pytest @pytest.fixture def app(): import yourapp return yourapp.make_app() # a tornado.web.Application
Create tests as native coroutines using Python 3.5+ async def:
async def test_app(http_server_client): resp = await http_server_client.fetch('/') assert resp.code == 200 # ...
When the plugin is installed, then pytest --fixtures will show the fixtures that are available:
- Port used by http_server.
Start a tornado HTTP server that listens on all available interfaces.
You must create an app fixture, which returns the tornado.web.Application to be tested.
Raises: FixtureLookupError: tornado application fixture not found
- Create an asynchronous HTTP client that can fetch from http_server.
- Create an asynchronous HTTP client that can fetch from anywhere.
- Create a new tornado.ioloop.IOLoop for each test case.
import time import tornado.web import tornado.gen import pytest class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, world!") @pytest.fixture def app(): return tornado.web.Application([(r"/", MainHandler)]) async def test_http_server_client(http_server_client): # http_server_client fetches from the `app` fixture and takes path resp = await http_server_client.fetch('/') assert resp.code == 200 assert resp.body == b"Hello, world!" async def test_http_client(http_client): # http_client fetches from anywhere and takes full URL resp = await http_client.fetch('http://httpbin.org/status/204') assert resp.code == 204 async def example_coroutine(period): await tornado.gen.sleep(period) async def test_example(): # no fixtures needed period = 1.0 start = time.time() await example_coroutine(period) elapsed = time.time() - start assert elapsed >= period
- minor updates to avoid a pytest warning under pytest 4
- repo switch to using a ‘src’ dir
- updated to work with Tornado 5, which is now the minimum required version
- require pytest >= 3.0
- the io_loop fixture always refers to a tornado.ioloop.IOLoop instance now
- the io_loop_asyncio and io_loop_tornado fixtures have been removed, since now that Tornado 5 always uses asyncio under Python 3, there would be no difference between the two fixtures, so io_loop is all that is needed
- tox tests now test more versions of Tornado (5.0.* and latest 5.*), Pytest (3.0.* and latest 3.*), and Python (3.5, 3.6, 3.7, and pypy3).