Skip to content
OVEX TECH
Education & E-Learning

Test Your FastAPI App with Pytest and Mocking

Test Your FastAPI App with Pytest and Mocking

How to Test Your FastAPI App with Pytest and Mocking

Learning to test your code is a crucial step in becoming a better programmer. This guide will show you how to test your Python FastAPI application using Pytest, a popular testing framework. You will learn how to set up your testing environment, write tests for your API routes, and even how to test parts of your code that rely on external services without actually using them.

We will cover setting up test structures and fixtures, which are like reusable pieces of code for your tests. You’ll also learn how to make database tests fast and isolated using a transactional rollback pattern. The guide includes testing common API actions like creating, reading, updating, and deleting data.

You will discover how to handle file uploads and ensure only the right people can access certain data. Finally, we will explore mocking, a technique that lets you pretend external services are working so your tests can run smoothly.

Prerequisites

Before you start, make sure you have Python installed on your computer. You should also be familiar with basic Python programming concepts and have a general understanding of web APIs. Having FastAPI installed and a basic project set up will be very helpful for following along.

1. Set Up Your Test Structure

First, let’s organize our tests. Create a new folder named ‘tests’ in the root of your project.

Inside this folder, create a file called conftest.py. This special file is where Pytest looks for fixtures and other configurations that can be shared across multiple test files.

We will place our main test fixtures here. Fixtures are functions that Pytest runs before or after your test functions.

They help set up the environment your tests need, like creating a test database or a test client for your API. This setup ensures each test starts from a clean slate.

2. Create a Test Client Fixture

Inside your conftest.py file, we need to set up a way to communicate with our FastAPI application during tests. We’ll use httpx.AsyncClient for this, as it works well with FastAPI’s asynchronous nature. This client acts like a web browser or a tool like Postman, but it runs directly within our test code.

We’ll define a fixture that creates an instance of this AsyncClient. This fixture will be available to any test function that requests it.

It’s important to set up this client to point to our FastAPI application instance. This allows our tests to send requests to our API and check the responses.

Tip: Transactional Rollback for Database Tests

Testing databases can be slow and messy if not handled carefully. A common pattern is to use transactional rollbacks.

This means that before each test that needs database access runs, we start a new database transaction. After the test finishes, whether it passes or fails, we roll back that transaction.

This process effectively undoes all the changes made during the test. It ensures that your database is always in the same state before each test runs, making your tests independent and reliable. You can implement this by using database features or specific libraries that help manage transactions within your test fixtures.

3. Write Basic API Route Tests

Now, let’s write our first tests. Create a new file in the ‘tests’ folder, for example, test_items.py.

Inside this file, you’ll write functions that start with test_. Pytest automatically finds and runs these functions.

For a simple API endpoint, like one that returns a list of items, your test function would use the test client fixture. It would send a GET request to the appropriate API path and then check if the response status code is 200 (which means ‘OK’) and if the returned data is what you expect. This is the fundamental structure for testing any API endpoint.

4. Test Authentication and Authorization

Many APIs require users to log in or have specific permissions. Testing these features is vital. For authentication tests, you might simulate a login request and check if a token is returned correctly.

For authorization, which is about checking if a user has permission to perform an action, you’ll need to test different user roles. For instance, a test could try to access a resource as a regular user and expect it to be forbidden, while accessing it as an administrator might be allowed. You’ll use the test client and potentially pass authentication tokens in your requests.

5. Test CRUD Operations

CRUD stands for Create, Read, Update, and Delete. These are the basic operations you perform on data in most applications. You should write tests for each of these operations for your API endpoints.

For example, a ‘Create’ test would send a POST request with new data and check if the response indicates success and if the data was stored correctly. A ‘Read’ test would fetch the data you just created.

An ‘Update’ test would modify existing data using a PUT or PATCH request and verify the changes. Finally, a ‘Delete’ test would remove the data and confirm it’s gone.

6. Test File Uploads

If your API handles file uploads, you need to test this functionality. This involves sending a POST request with a file attached. You can create a dummy file in your test code for this purpose.

Your test should verify that the file was received correctly by the server, perhaps by checking the response or by trying to access the uploaded file. It’s also good practice to test error cases, like uploading a file that’s too large or of the wrong type.

7. Mocking External Services

Sometimes, your API needs to interact with other services, like sending emails or storing files in cloud storage (e.g., AWS S3). Testing these interactions directly can be slow, expensive, or unreliable because they depend on external systems.

This is where mocking comes in. Mocking allows you to replace a real external service with a fake one during your tests.

For instance, instead of actually sending an email, you can mock the email service to just record that an email was supposed to be sent. Libraries like pytest-mock or moto (for AWS services) are very useful here.

Example: Mocking AWS S3

To mock AWS S3, you can use the moto library. You would typically use a decorator provided by moto to tell your tests to intercept any calls to AWS services.

When your code tries to upload a file to S3, moto will pretend to handle the request. Your test can then check if the correct S3 upload function was called with the expected arguments, without actually touching AWS. This makes your tests fast and independent of AWS being available.

8. Test Background Tasks

FastAPI applications often use background tasks to perform operations that don’t need to block the user’s request, like sending a welcome email after a user signs up. Testing these tasks requires a different approach.

You might need to configure your test environment to capture or execute these background tasks immediately. This allows you to check if the task was queued correctly and if it completed successfully. The exact method will depend on how background tasks are implemented in your application.

Conclusion

By implementing these testing strategies, you can build confidence in your FastAPI application’s reliability and correctness. You have learned how to set up your test environment, write tests for various API functionalities, and use mocking to handle external dependencies.

These patterns will help you catch bugs early and make changes to your code with greater certainty. Remember to consult the project’s GitHub repository for the complete code example. You can find the code from this tutorial at https://github.com/CoreyMSchafer/FastAPI-17-Testing.


Source: Python FastAPI Tutorial (Part 17): Testing the API – Pytest, Fixtures, and Mocking External Services (YouTube)

Leave a Reply

Your email address will not be published. Required fields are marked *

Written by

John Digweed

2,961 articles

Life-long learner.