Testing API Responses
Tornado OpenAPI 3 includes a base test class to help you validate each of your application’s responses while you test its behavior.
Making your tests aware of your API specification
By extending AsyncOpenAPITestCase, you can
define your test cases with your specification attached. Every response returned
by fetch() will be
automatically checked against your specification to ensure they match the
formats documented, and exceptions will be raised when they do not.
Because it extends tornado.testing.AsyncHTTPTestCase, you can write
your application tests as you normally would with added confidence that your API
is behaving exactly as you expect it to.
import unittest
import tornado.web
from tornado_openapi3.testing import AsyncOpenAPITestCase
class RootHandler(tornado.web.RequestHandler):
async def get(self):
self.finish("Hello, World!")
class BaseTestCase(AsyncOpenAPITestCase):
spec_dict = {
"openapi": "3.0.0",
"info": {
"title": "Simple Example",
"version": "1.0.0",
},
"paths": {
"/": {
"get": {
"responses": {
"200": {
"description": "Index",
"content": {
"text/html": {
"schema": {"type": "string"},
}
},
}
}
}
}
},
}
def get_app(self):
return tornado.web.Application([(r"/", RootHandler)])
def test_root_endpoint(self):
response = self.fetch("/")
self.assertEqual(200, response.code)
self.assertEqual(b"Hello, World!", response.body)
if __name__ == "__main__":
unittest.main()
Adding custom deserializers
If your endpoints make use of content types beyond application/json, you
must add them to this dictionary with a deserializing method that converts the
raw body (as bytes or str) to Python objects.
import json
from tornado_openapi3.testing import AsyncOpenAPITestCase
class TestCase(AsyncOpenAPITestCase):
custom_media_type_deserializers = {
"application/vnd.example.resource+json": json.loads,
}
...
Adding custom formatters
If your schemas make use of format modifiers, you may specify them in this
dictionary paired with a Formatter object that
provides methods to validate values and unmarshal them into Python objects.
import datetime
from tornado_openapi3.testing import AsyncOpenAPITestCase
class USDateFormatter:
def validate(self, value: str) -> bool:
return bool(re.match(r"^\d{1,2}/\d{1,2}/\d{4}$", value))
def unmarshal(self, value: str) -> datetime.date:
return datetime.datetime.strptime(value, "%m/%d/%Y").date()
class TestCase(AsyncOpenAPITestCase):
custom_formatters = {
"usdate": USDateFormatter(),
}
...