Introduction
This post explains how to mock your API dependencies while testing. While creating routes in fastapi
, we usually add dependencies for various reasons. To name a few, decoding a jwt token or parsing a request body. Using dependencies makes your code more readable and concise.
If you’re new to fastapi, please read this article to get
Dependencies in fastapi
Let’s write a simple API with dependencies in fastapi in a python module fastapi_dependency.py
.
FastAPI has a very powerful but intuitive Dependency Injection system.FastAPI will take care of doing whatever is needed to provide your code with those needed dependencies. The above code explains how dependency injection works in fastapi
.
The Depends
keyword is defined by the fastapi and we leverage the same to declare and inject our dependencies into the fastapi routes. Here, get_user_name
() is a dependant function that decodes an username from the headers.
Depends
function takes a single parameter and all the request parameters are automatically passed to your dependency.
Accessing the /users
endpoint gives the below output.
Output
Mocking dependencies:
We have our code up and running now. Let’s say we need to write unit test for the above code. We cannot pass an actual auth token in unit tests. Instead, we need to mock them. However, mocking the dependencies may be cumbersome as they are injected during run-time.
Fastapi provides a convenient mechanism to override the actual dependencies under test. It has an attribute called app.dependency_overrides
which is a python dict
.
test_fastapi_dependency.py
from fastapi.testclient import TestClient
from fastapi_dependency import get_user_name
# please note the app should be imported from the actual module under test.
# else you may get 404 errors
from fastapi_dependency import app
# Initialise a test client
client = TestClient(app)
# mocked get username function
async def mock_get_user_name():
return {
"user":
{
"name": "testuser"
}
}
# using dependency overrides to mock the function get_user_name
app.dependency_overrides[get_user_name] = mock_get_user_name
def test_user():
"""
Tests an endpoint /users with a mock token
"""
response = client.get(url="/users",
headers={
"Authorization": "Bearer some-token"
})
assert response.status_code == 200
assert response.json().get('user') == {'user': {'name': 'testuser'}}
A caveat here is, you should import the _app_
object from the module under test and not create a new _fastapi_
app object here. Creating a new object in the test function will return HTTP 404 errors.
The app object has dependency overrides
function as a dictionary. Assigning the dependency to this dictionary as a key and the mock function as a value, we should be able to override the dependencies quite easily. You can set a dependency override for a dependency used anywhere in your FastAPI application.
I personally love these kind of “batteries included” features in fastapi. Next time when you use fastapi and are reluctant to use dependencies because of unit testing hassles, please don’t think twice. Just go ahead and use the dependency overrides.
Originally published in dock2learn on December 14th 2022.
References:
- https://fastapi.tiangolo.com/advanced/testing-dependencies/#use-the-appdependency%5Foverrides-attribute
- https://fastapi.tiangolo.com/tutorial/dependencies/#import-depends