JavaRush /Курсы /Модуль 4: FastAPI /Пример написания полного набора тестов для API

Пример написания полного набора тестов для API

Модуль 4: FastAPI
5 уровень , 9 лекция
Открыта

Сегодня мы напишем полный набор тестов для FastAPI-приложения. Мы пройдёмся по всем ключевым возможностям API и убедимся, что наше приложение работает как часики. Для этого мы:

  • Научимся организовывать тесты так, чтобы они были структурированными;
  • Покроем основные кейсы, включая безопасные эндпоинты, обработку ошибок и проверку бизнес-логики;
  • Разберёмся, как писать тесты, которые не только проверяют работоспособность приложения, но и помогают обнаружить углы, о которых мы могли не подумать.

Пример приложения: база данных пользователей

Для тестирования мы возьмём небольшое приложение, которое мы разрабатывали ранее — базу данных пользователей с CRUD-операциями. Вот его основные эндпоинты:

  • GET /users/ — получение списка пользователей.
  • GET /users/{user_id} — получение данных конкретного пользователя.
  • POST /users/ — создание нового пользователя.
  • PUT /users/{user_id} — обновление данных пользователя.
  • DELETE /users/{user_id} — удаление пользователя.

Кроме того, приложение поддерживает:

  • Валидацию данных через Pydantic;
  • Аутентификацию через JWT;
  • Обработку кастомных ошибок (например, если пользователь не найден).

Перед тестированием убедитесь, что структура вашего проекта выглядит примерно так:

project/
├── app/
│   ├── main.py
│   ├── models.py
│   ├── schemas.py
│   ├── database.py
│   ├── routers/
│   │   └── users.py
├── tests/
│   └── test_users.py

План тестирования

Весь процесс тестирования мы разобьём на следующие этапы:

  1. Тестирование публичных эндпоинтов (GET-запросы).
  2. Тестирование защищённых эндпоинтов (POST, PUT, DELETE).
  3. Проверка обработки ошибок.
  4. Работа с фикстурами для ускорения написания тестов.
  5. Проверка покрытия кода.

Тестирование публичных эндпоинтов

Первым делом протестируем, как работает получение данных через GET /users/ и GET /users/{user_id}. Для этого мы будем использовать встроенный TestClient из FastAPI.

Пример теста для получения списка пользователей


from fastapi.testclient import TestClient
from app.main import app

client = TestClient(app)

def test_get_all_users():
    response = client.get("/users/")
    assert response.status_code == 200
    assert isinstance(response.json(), list)  # Ответ должен быть списком

Пример теста для получения конкретного пользователя


def test_get_user_by_id():
    user_id = 1
    response = client.get(f"/users/{user_id}")
    assert response.status_code == 200
    data = response.json()
    assert data["id"] == user_id
    assert "email" in data  # Проверяем наличие ожидаемых полей

Тестирование защищённых эндпоинтов

Поскольку некоторые эндпоинты требуют аутентификацию, нам нужно будет передавать корректный JWT-токен. В реальных приложениях вы, скорее всего, будете тестировать не только корректные токены, но и сценарии, когда они отсутствуют или невалидны.

Фикстура для создания токена


import jwt
from datetime import datetime, timedelta

SECRET_KEY = "supersecretkey"

def get_test_token(user_id: int):
    payload = {
        "sub": user_id,
        "exp": datetime.utcnow() + timedelta(minutes=15)
    }
    return jwt.encode(payload, SECRET_KEY, algorithm="HS256")

Пример теста для создания пользователя


def test_create_user():
    token = get_test_token(user_id=1)
    headers = {"Authorization": f"Bearer {token}"}
    payload = {
        "email": "testuser@example.com",
        "name": "Test User",
        "age": 25
    }
    response = client.post("/users/", json=payload, headers=headers)
    assert response.status_code == 201
    data = response.json()
    assert data["email"] == payload["email"]

Тестирование обработки ошибок

Ошибки — это как баги, только ожидаемые. Поэтому мы должны убедиться, что наше приложение корректно обрабатывает ситуации, когда, например, пользователь запрашивает несуществующий ресурс.

Пример теста для получения несуществующего пользователя


def test_get_nonexistent_user():
    user_id = 999  # Если такого пользователя нет
    response = client.get(f"/users/{user_id}")
    assert response.status_code == 404
    assert response.json() == {"detail": "User not found"}

Использование фикстур

Чтобы избежать дублирования кода (например, создания пользователей в каждом тесте), мы можем использовать фикстуры Pytest.

Фикстура для подготовки данных


import pytest

@pytest.fixture
def new_user():
    return {"email": "fixtureuser@example.com", "name": "Fixture User", "age": 30}

Использование фикстуры в тестах


def test_create_user_with_fixture(new_user):
    token = get_test_token(user_id=1)
    headers = {"Authorization": f"Bearer {token}"}
    response = client.post("/users/", json=new_user, headers=headers)
    assert response.status_code == 201
    assert response.json()["email"] == new_user["email"]

Проверка покрытия кода

После написания всех тестов мы должны убедиться, что покрыли большую часть нашего приложения. Для этого мы будем использовать плагин pytest-cov.

Установка pytest-cov:

pip install pytest-cov

Запуск тестов с покрытием:

pytest --cov=app

Результат будет выглядеть примерно так:

----------- coverage: platform linux, python 3.x -----------
Name                              Stmts   Miss  Cover
-----------------------------------------------------
app/main.py                          18      0   100%
app/models.py                        15      2    87%
app/schemas.py                       21      1    95%
app/routers/users.py                 42      3    93%
-----------------------------------------------------
TOTAL                                96      6    94%

Организация структуры тестов

Если ваши тесты разрастутся, возможно, вы захотите организовать их по модулям или функциональности. Например:

tests/
├── test_users.py
├── test_auth.py
├── test_errors.py

Итоговый пример полного набора тестов

Вот примерные тесты, которые можно включить в ваш проект:

  1. Тесты для всех CRUD-операций (GET, POST, PUT, DELETE);
  2. Проверка защитных механик (валидация токенов, доступ к защищённым ресурсам);
  3. Обработка ошибок (404, некорректные данные);
  4. Тестирование с использованием фикстур;
  5. Убедиться в высокой степени покрытия кода.

С таким подходом вы будете спать спокойно и знать, что ваше API готово к любым испытаниям.

1
Задача
Модуль 4: FastAPI, 5 уровень, 9 лекция
Недоступна
Тестирование POST-запроса для создания пользователя
Тестирование POST-запроса для создания пользователя
1
Задача
Модуль 4: FastAPI, 5 уровень, 9 лекция
Недоступна
Тестирование исключений при запросе несуществующего пользователя
Тестирование исключений при запросе несуществующего пользователя
3
Опрос
Тестирование аутентификации через JWT, 5 уровень, 9 лекция
Недоступен
Тестирование аутентификации через JWT
Тестирование аутентификации через JWT
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ