Alexander Hultnér
Founder, Hultnér Technologies (https://hultner.se). Want me to speak at your company? Corporate training? Or just a fresh pair of eyes on your project? Contact me for contracts.
Automatically generate test-cases based on your API-schemas with schemathesis
Alexander Hultnér, EuroPython, 2020
@ahultner
Founder of Hultnér Technologies
@ahultner
@ahultner
API Schemas increasingly more popular. Today's focus on OpenAPI.
@ahultner
There's plenty of libraries implementing OpenAPI.
Some examples:
Python Implementations of Swagger/OpenAPI
@ahultner
@ahultner
Spectrum of defects, not all errors are equal but they're never good
@ahultner
Property based testing with Hypothesis
Property based testing (PBT) is great at finding corner casing.
Let the computer do the heavy lifting in creating exhaustive tests.
@ahultner
The defacto standard for PBT in Python. A property models the behaviour of a piece of code given a certain type of input.
Modelling properties
To test the application we need to model the properties and their input, but can we do better?
Schemas specify the expected behaviour of application for a defined type of input, sounds a bit like properties, doesn't it?
Can we leverage this? Yes we can with Schemathesis!
@ahultner
Model properties and strategies from schemas
Automatically generates test cases based on what we already know about or application from our specs.
@ahultner
History, influences and related works
Standalone library but other works have influenced some features and ideas.
@ahultner
What do we already know?
Turns out we already know quite a bit about our application
@ahultner
# Pseudo code
r = response
r.status_code < 500
r.status_code in endpoint.responses
r.headers['Content-Type']
in endpoint.responses[r.status_code]
matches_spec(
r.content,
endpoint
.responses[r.status_code]
[r.headers['C…-Type'] # schema spec
)
Let's pray to the demo god's!
@ahultner
As you could see lot's for random requests
were generated for us!
What can schemathesis do more?
Schemathesis can do quite a lot and more is coming!
@ahultner
CLI Interface
Schemathesis implements a rather comprehensive CLI-interface, exposing a lot of the functionality.
Well documented under
$ schemathesis [CMD] --help
$ schemathesis run http://127.0.0.1:5000/swagger.json
================== Schemathesis test session starts ==================
platform …
rootdir: /~/dev/hultner_technologies/Schema-based-API-Testing/code
hypothesis profile 'default' -> database=Directory…
Schema location: http://127.0.0.1:5000/swagger.json
Base URL: http://127.0.0.1:5000/
Specification version: Swagger 2.0
Workers: 1
collected endpoints: 5
GET /todos/ . [ 20%]
POST /todos/ . [ 40%]
DELETE /todos/{id} . [ 60%]
GET /todos/{id} . [ 80%]
PUT /todos/{id} . [100%]
============================== SUMMARY ===============================
Performed checks:
not_a_server_error 500 / 500 passed PASSED
========================= 5 passed in 5.32s ==========================
Minimal example
@ahultner
CLI Interface, WSGI/ASGI interface vs HTTP interface
I use both, it's great to test the entire chain for a true end to end test.
The WSGI/ASGI interface is useful for quicker local branch testing and for larger amounts of examples/data.
$ schemathesis run --app=flask_example:app /swagger.json
================== Schemathesis test session starts ==================
platform Darwin -- Python 3.8.2, schemathesis-2.0.0, hypothesis-5.…
rootdir: /~/dev/hultner_technologies/Schema-based-API-Testing/code
hypothesis profile 'default' -> database=DirectoryBasedExample…s')
Schema location: /swagger.json
Base URL: /
Specification version: Swagger 2.0
Workers: 1
collected endpoints: 5
GET /todos/ . [ 20%]
POST /todos/ . [ 40%]
GET /todos/{id} . [ 60%]
DELETE /todos/{id} . [ 80%]
PUT /todos/{id} . [100%]
============================== SUMMARY ===============================
Performed checks:
not_a_server_error 500 / 500 passed PASSED
========================= 5 passed in 3.73s ==========================
WSGI Flask example
@ahultner
HTTP Interface is framework, even language agnostic.
Test any service with a schema specification, be it Python or Cobol.
pytest interface
Schemathesis can be used to generate test-cases for pytest where we can define our own properties. Can cover the entire schema or single endpoint/method.
Previously mentioned built in checks:
@ahultner
Some suggestions to extend with:
pytest interface
From the documentation, tests that any data fitting the schema doesn't cause a server error
@ahultner
# test_api.py
import requests
import schemathesis
schema = schemathesis.from_uri("http://0.0.0.0:8080/swagger.json")
@schema.parametrize()
def test_no_server_errors(case):
# `requests` will make an appropriate call under the hood
response = case.call() # use `call_wsgi` if you used `schemathesis.from_wsgi`
# You could use built-in checks
case.validate_response(response)
# Or assert the response manually
assert response.status_code < 500
Stateful testing
Shown to enhance detection of certain defects in the QuickREST research, recently added to schemathesis.
Requires links between objects, feature came with OpenAPI 3.0, but can be used with 2.0/Swagger with the x-links extension.
(will not work with Flask-RESTX out of the box)
@ahultner
schemathesis run --stateful=links http://0.0.0.0/swagger.yaml
...
POST /api/users/ . [ 33%]
-> GET /api/users/{user_id} . [ 50%]
-> PATCH /api/users/{user_id} . [ 60%]
-> PATCH /api/users/{user_id} . [ 66%]
GET /api/users/{user_id} . [ 83%]
-> PATCH /api/users/{user_id} . [ 85%]
PATCH /api/users/{user_id} . [100%]
...
Schemathesis of tomorrow
We need your help to grow!
@ahultner
@ahultner
Contact me if you have any further
questions.
#talk-testing-with-schemathesis
Want to learn more?
Available for training, workshops and freelance consulting.
Previous Hypothesis talk on YouTube
@ahultner
By Alexander Hultnér
Automatically generate test-cases based on your API-schemas with Schemathesis.
Founder, Hultnér Technologies (https://hultner.se). Want me to speak at your company? Corporate training? Or just a fresh pair of eyes on your project? Contact me for contracts.