Flask API Unit Testing
Testing
- Case
# given# when# thenassert trueKacper Walczak · 01-05-2024
Learn how to unit test your APIs.
Introduction
This is the third part of the series about Flask JSON API.
You don't need to have any previous code. But if you want to catch up, you can follow the first/second article or clone the repository from GitHub (opens in a new tab).
This article is a part of the Flask JSON API series.
Unit testing
Unit testing is a type of testing that tests individual units of code. In this case, we will unit test our endpoints.
Endpoints make calls to a services, grabs/persists data, and returns it.
We should test if the endpoint internal service calls are correct and if the response is as expected.
What to test?
Let's look at the following endpoint and get_data(data_id, user) method.
class Service:
def __init__(self, repository, notifier):
self.repository = repository
self.notifier = notifier
def get_data(self, data_id, user):
data = self.repository.get(data_id)
self.notifier.notify(data, { "fetch_by": user })
return {"list": data}
def endpoint(request, data_id):
repo = Repository()
notifier = Notifier()
service = Service(repo, notifier)
data = service.get_data(data_id, request.user)
return data.get("list", [])Testing Service
To test service we should test if:
- service.
get_datais called and returns proper data for a given set of arguments - notifier is called with proper arguments, but we can omit it due to the fact that this will be tested in the integration test like:
test_get_gata_and_notifyand we want to unit test whole flow not side effects
Make another test for the notifier if you want to test it separately with e.g.
mocks.
Testing get_data
To test get_data we need testing repository and notifier.
class Service:
def get_data(self, data_id, user):
data = self.repository.get(data_id)
self.notifier.notify(data, { "fetch_by": user })
return {"list": data}Once we get here we can understand that we have to:
- make an
abstraction for repository and notifier services.
Repository and Notifier ABC
These are abstract classes that we can use to define the interface for the repository and notifier.
They allow us to easily swap the implementation of the repository and notifier. We can use the actual repository and notifier in the production code and the testing repository and notifier in the testing code.
It is way better than using mocks.
We will be able to
REUSEthe testing repository and notifier in other tests.
from abc import ABC, abstractmethod
from typing import List, Any
class RepositoryABC(ABC):
@abstractmethod
def get(self, data_id) -> List[Any]:
pass
class NotifierABC(ABC):
@abstractmethod
def notify(self, data, meta):
passTesting Repository and Notifier
With this approach we can easily stub the repository and notifier services with an actual testing the system.
class TestRepository(RepositoryABC):
data = {
"1": [1]
}
def get(self, data_id):
return self.data.get(data_id, [])
class TestNotifier(NotifierABC):
def notify(self, data, meta):
passAn Actual Test
Now we can test get_data the service without any mocks.
def test_get_data_for_fake_id():
# given
test_repository = TestRepository()
test_notifier = TestNotifier()
service = Service(test_repository, test_notifier)
data_id = "fake_data_id"
user = "fake_user"
# when
returned_data = service.get_data(data_id, user)
# then
assert returned_data == [] # we return empty list for non-existing/fake data_idTesting Endpoint
Testing endpoint should be done only if the service is tested and more logic or data manipulation is done in the endpoint.
Most likely, you will test the endpoint like this in the integration tests.
Integration testing
Integration testing is a type of testing that tests the integration of multiple units of code. In this case, we will test the endpoints.
Difference between unit and integration testing
Unit testing tests individual units of code. In this case, we tested the service.
Integration testing tests the integration of multiple units of code at once. In this case, we will test the endpoints.
Actual integration test example
You can test endpoints that uses services easily.
def test_make_post_from_non_existing_draft(client): # client from first article
# given
post_draft_id = "fake_post_draft_id_here"
# when
make_post_from_non_existing_draft_response = client.post(
"/make_post_from_draft",
json={"post_draft_id": post_draft_id},
)
# then
assert make_post_from_non_existing_draft_response.status_code == 404Next
That's it! Now you can use this as a base for your extended testing needs with JSON API.
You can go to the following articles about Flask JSON API series.
This article is a part of Flask JSON API series.
READ
Latest readings
Readings are sites which will help you with detailed
information about given topic. Read latest ones from Learn.
06-03-2026
Build your own local voice assistant powered by Ollama.
06-03-2026
Generate YouTube thumbnails with FastAPI and Ollama.
05-09-2024
Compare Neo4j and Tigergraph databases, which is easier to work with, etc.