Serverless FastAPI Testing: Use Moto and Just Mock It!

Serverless FastAPI Testing: Use Moto and Just Mock It!

In my previous blog post Serverless FastAPI Development: Building Player FC API on AWS, we explored creating and deploying a FastAPI application on AWS. In this blog post we’ll take a look at testing our app locally.

We write tests to prove that our code works as designed, however since our code interacts with cloud services it’s somewhat of a challenge to mock tests to the cloud without actually making api calls that traverse the internet, well that is unless you use Moto.

Moto is a Python library that mocks AWS services, allowing you to test without making real API calls.

Why Mock AWS Services?

When it comes to testing applications that interact with cloud services like AWS, mocking becomes essential for a couple of practical reasons.

First, cloud services cost money. Testing against resources deployed in the cloud isn’t free.

Secondly, an active & reliable internet connection is required, it’s not ideal to have your tests bound to the internet. You might find yourself at a conference with slow and limited wifi connectivity or a space with public wifi that shouldn’t be trusted. You could be on a plane or train, you might even find yourself in a remote area.

Mocking allows you to run tests locally without incurring additional costs. Everyone loves to save money after all.

Setting Up Your Test Environment

Some preparation is required to ensure we can run our tests, we need a way for our tests to import modules that we have written as well letting pytest know where these files are located.

This can be achieved by creating a conftest.py file as well as a pyproject.toml file.

  • conftest.py file gets the absolute path of the project root directory.
  • pyproject.toml file sets the path for our app, test paths and silences a deprecation warning for botocore.

Create these files at your project’s root:

Your First Test: The Root Endpoint

Create a directory that will be a home for our tests, name it tests and within this directory create a file named test_player.py.

Let’s create a test for our root endpoint, add the following imports at the top of the file:

Create a TestClient object and pass app as an argument, add a test function named test_root, see below for the complete code snippet:

Run pytest test_player.py::test_root in the terminal window. The test should pass.

Create Pytest Fixtures

We will use Fixtures to provide a defined, reliable and consistent context for our tests. This will include player data, mocked AWS credentials for moto and our mock DynamoDB table.

Let’s add a couple of fixtures to our code, we will start with creating a fixture that contains a single player’s data, add this code directly below the client object we created earlier:

Now we need to take a similar approach for representing all players, however creating a function with all this data will make the code long, a better approach would be to create a separate json file and load the data when the function is called.

Create a file named players.json in the tests directory and populate it with the below:

Add the below code to create a fixture that will load the all players data from the json file when the function is called:

Mocking AWS credentials and DynamoDB service

Create a fixture that will mock AWS credentials for below by adding the below code:

The mocked AWS credentials will be used as an argument for our mock DynamoDB table, add the below code to create another fixture for mocking the AWS DynamoDB service:

CRUD Testing Journey

With all the fixtures created, we are now at a stage that we can begin testing the other endpoints that would normally interact with AWS services, albeit mocked in nature.

We can create a test that will create and return the player data, this function takes in the dynamodb_table and player_data fixtures we created earlier as arguments, add the below code:

Run pytest test_player.py::test_create_and_get_player, this test too shall pass.

Onto the next endpoint, lets test if we can get all players, this will be achieved by loading the players data from a json file and asserting that players names are found and if a certain player is not found.

Run pytest test_player.py::test_get_all_players

We’re on a roll with tests that are passing at this stage, lets test the endpoint for updating a player details, the player in question is Christopher Nkunku, he will be transferring to Bayern Munich and will take up the number 10 jersey.

Run pytest test_player.py::test_update_player

Now let’s create a test for removing a player.

Run pytest test_player.py::test_delete_player

The final test is an edge case, lets create a test when removing a non existent player, an error 404 should be returned since the player does not exist.

Run pytest test_player.py::test_delete_non_existent_player

Conclusion

Now that you’ve learnt how to mock AWS services with Moto, you’re ready for the next steps: deploying your FastAPI app and integrating these tests into a CI/CD pipeline.
I’ll cover that in a future post. Until then, happy testing ⚡️🐍

Author

Adrian Mudzwiti

Posted on

2025-06-21

Updated on

2025-06-21

Licensed under

Comments