Contract Testing with HTTPX
Today, we are going to talk about how to achieve contract testing with HTTPX.
What is contract testing?
Contract testing is a methodology for ensuring that two separate systems (such as two microservices) are compatible and are able to communicate with one other. It captures the interactions that are exchanged between each service, storing them in a contract, which can then be used to verify that both parties adhere to it. - Matt Fellows
What is HTTPX?
HTTPX is a fully featured HTTP client for Python 3, which provides sync and async APIs, and support for both HTTP/1.1 and HTTP/2.
How to do contract testing with HTTPX?
Well, to be completely transparent, I'm not sure if what you are about to read classifies as contract testing.
The problem we'll be trying to solve is the following:
Consider we have multiples services running, and they depend on each other. We want to make sure that a service is not able able to break another one.
To achieve this your first thought would be "let's write end to end tests", but that will slow things down, as each service needs to be up to run the tests, and given that, the setup needed is a bit more complex.
Check this blog post (which I didn't read, but looks good) for more information about E2E testing vs Contract Testing.
The solution
Let's assume we have two services. For obvious reasons, those services are FastAPI based.
Note
This can be achieved with any web framework. What matters here is that you should be using httpx
.
- The port is 8001, not 8000, to avoid conflicts with the other service.
Cool. Now, let's call the /a/call_b
endpoint:
- The HTTP client used is called HTTPie, but you can use
curl
, or just go to the browser, and accesshttp://localhost:8001/a/call_b
.
As we see, the response is:
Now, if we want to create a test, we can do something like:
test_service_a.py | |
---|---|
See more on the Starlette documentation.
See more on the Starlette documentation.
That works perfectly, right?
Well, yes. But remember what I said in the beginning?
To achieve this your first thought would be "let's write end to end tests", but that will slow things down, as each service needs to be up to run the tests, and given that, the setup needed is a bit more complex.
So, what if we want to run the tests without having to run the services?
Patch the HTTP client
We can patch the HTTPX client to make it call the service B, without actually running the service B.
To achieve that, we'll be using RESPX: a simple library,
yet powerful, for mocking out the HTTPX
and HTTPCore
libraries.
It's easy, let me show you! We just need to add a single fixture on the test_service_a.py
file:
-
The
respx.mock
context manager is used to mock the HTTPX client.Read more about it on the RESPX documentation.
-
The
respx.mock
context manager is used to mock the HTTPX client.Read more about it on the RESPX documentation.
Nice! We did it!
Now, we can run the tests without having to run the services.
If you are a curious person, feel free to compare the tests with the time
command:
Be surprised.
Info
You can also read the continuation of this article here.