Ответ
Тестирование такого эндпоинта можно разделить на два основных подхода: модульное (unit) тестирование с изоляцией БД и интеграционное тестирование с реальной тестовой базой данных.
1. Модульный тест с использованием Mock-объектов
Этот подход изолирует слой API (view, controller) от базы данных. Мы заменяем вызов к БД "заглушкой" (mock), которая возвращает предопределенные данные. Это делает тесты очень быстрыми и независимыми от состояния БД.
Цель: Проверить логику эндпоинта: обработку запроса, сериализацию данных и формирование HTTP-ответа.
Пример с unittest.mock:
from unittest.mock import patch
from flask import Flask
# Предположим, это наш код приложения
app = Flask(__name__)
def get_users_from_db():
# ... здесь реальный код для запроса к БД
pass
@app.route('/api/users')
def get_users():
users = get_users_from_db()
return {'data': users}
# Тест
@patch('__main__.get_users_from_db') # Путь к мокируемой функции
def test_get_users_endpoint(mock_get_users):
# Arrange: настраиваем mock
mock_return_data = [{'id': 1, 'name': 'Alice'}]
mock_get_users.return_value = mock_return_data
# Act: делаем запрос к эндпоинту
with app.test_client() as client:
response = client.get('/api/users')
# Assert: проверяем результат
assert response.status_code == 200
assert response.json == {'data': mock_return_data}
mock_get_users.assert_called_once() # Убеждаемся, что функция была вызвана
2. Интеграционный тест с тестовой базой данных
Этот подход проверяет взаимодействие всех компонентов системы: HTTP-сервер, код эндпоинта, ORM и базу данных. Тесты выполняются на отдельной, изолированной тестовой БД, которая создается и очищается для каждого тестового запуска.
Цель: Убедиться, что SQL-запросы корректны, ORM-маппинг работает, и вся цепочка от запроса до ответа функционирует как единое целое.
Пример с pytest и pytest-django:
import pytest
from django.urls import reverse
from rest_framework.test import APIClient
from myapp.models import User
@pytest.mark.django_db
def test_get_users_integration():
# Arrange: создаем реальные данные в тестовой БД
User.objects.create(username='bob', email='bob@example.com')
client = APIClient()
url = reverse('user-list') # Получаем URL эндпоинта
# Act: делаем запрос
response = client.get(url)
# Assert: проверяем реальный ответ, сформированный на основе данных из БД
assert response.status_code == 200
assert response.json() == [
{
'username': 'bob',
'email': 'bob@example.com'
}
]
Какой подход выбрать?
- Модульные тесты идеальны для сложной бизнес-логики внутри эндпоинта. Они быстрые.
- Интеграционные тесты необходимы для проверки корректности работы с БД и являются более надежным показателем работоспособности фичи. Обычно их пишут для ключевых сценариев использования.