Тестирование — важная часть разработки любых приложений, включая те, что строятся с использованием FastAPI. Это помогает убедиться, что приложение работает как ожидается, и упрощает поддержку кода в будущем. В этой статье мы рассмотрим основы тестирования FastAPI-приложений, включая тестирование маршрутов, зависимостей и работу с мокированием базы данных. Мы также посмотрим, как использовать pytest для написания тестов, а также как эффективно мокировать компоненты для изоляции тестов.
Основы тестирования с pytest
Для тестирования FastAPI-приложений мы будем использовать библиотеку pytest. Это популярная библиотека для тестирования Python, которая имеет удобный синтаксис и множество встроенных возможностей, таких как параллельное выполнение тестов, фикстуры и возможность использования моков.
FastAPI и pytest отлично интегрируются друг с другом. Для тестирования API-маршрутов можно использовать TestClient от FastAPI, который позволяет отправлять HTTP-запросы к вашему приложению и проверять ответы.
Установка зависимостей:
pip install pytest fastapi
Тестирование маршрутов и зависимостей
Пример теста для маршрута
Предположим, у нас есть простое приложение FastAPI с маршрутом для получения информации о пользователе:
from fastapi import FastAPI
app = FastAPI()
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"user_id": user_id, "name": "John Doe"}
Чтобы протестировать этот маршрут, создадим тест с использованием TestClient:
from fastapi.testclient import TestClient
from myapp import app # Импортируем приложение FastAPI
client = TestClient(app)
def test_get_user():
response = client.get("/users/1")
assert response.status_code == 200
assert response.json() == {"user_id": 1, "name": "John Doe"}
Пояснение:
- TestClient(app) — создает клиента для взаимодействия с приложением FastAPI. Это позволяет отправлять запросы без запуска сервера.
- client.get(«/users/1») — отправляем GET-запрос на маршрут /users/1.
- assert response.status_code == 200 — проверяем, что статус код ответа равен 200, что означает успешное выполнение запроса.
- assert response.json() == {«user_id»: 1, «name»: «John Doe»} — проверяем, что тело ответа соответствует ожидаемому JSON-объекту.
Использование TestClient
TestClient в FastAPI позволяет нам тестировать API так, как если бы мы взаимодействовали с реальным сервером, но без необходимости запускать его. Он поддерживает все HTTP-методы и позволяет тестировать ответы, заголовки, статус коды и другие параметры.
Пример теста для POST-запроса
from fastapi.testclient import TestClient
from myapp import app
client = TestClient(app)
def test_create_user():
user_data = {"name": "Alice", "age": 30}
response = client.post("/users/", json=user_data)
assert response.status_code == 201
assert response.json() == {"name": "Alice", "age": 30}
Мокирование БД и зависимостей
В реальных приложениях с FastAPI, скорее всего, будет использоваться база данных для хранения данных, например, PostgreSQL или MySQL. В тестах может возникнуть необходимость изолировать взаимодействие с базой данных, чтобы не работать с настоящими данными. Для этого используется мокирование (замена реальной базы данных на фиктивную, которая будет эмулировать нужное поведение).
Пример мокирования зависимости
Предположим, у нас есть сервис, который взаимодействует с базой данных для получения информации о пользователе:
from fastapi import Depends
class Database:
def get_user(self, user_id: int):
return {"user_id": user_id, "name": "John Doe"}
def get_database():
return Database()
@app.get("/users/{user_id}")
async def get_user(user_id: int, db: Database = Depends(get_database)):
user = db.get_user(user_id)
return user
В тестах мы можем мокировать зависимость get_database, чтобы избежать обращения к реальной базе данных:
from unittest.mock import MagicMock
from fastapi.testclient import TestClient
from myapp import app, get_database
client = TestClient(app)
def test_get_user_with_mock():
mock_db = MagicMock()
mock_db.get_user.return_value = {"user_id": 1, "name": "Mocked User"}
# Мокируем зависимость get_database
app.dependency_overrides[get_database] = lambda: mock_db
response = client.get("/users/1")
assert response.status_code == 200
assert response.json() == {"user_id": 1, "name": "Mocked User"}
Написание тестов для обработки ошибок
Важно тестировать не только успешные сценарии, но и случаи, когда происходят ошибки. Например, если пользователь запрашивает несуществующего пользователя, сервер должен вернуть ошибку 404.
Пример теста для ошибки
def test_get_user_not_found():
response = client.get("/users/999") # Пользователя с ID 999 не существует
assert response.status_code == 404
assert response.json() == {"detail": "User not found"}
Заключение
Тестирование FastAPI-приложений с использованием pytest и TestClient — это мощный и гибкий инструмент для создания качественного кода. Важно не только проверять успешные сценарии, но и тестировать обработку ошибок, мокировать зависимости и базы данных, чтобы изолировать тесты и не зависеть от внешних ресурсов. В этой статье мы рассмотрели основы тестирования маршрутов, работы с моками и тестирования ошибок. Теперь у вас есть все необходимое для того, чтобы уверенно писать тесты для вашего FastAPI-приложения.
Тестирование — это не просто хорошая практика, а неотъемлемая часть процесса разработки, которая помогает создать надежные и масштабируемые приложения.