Ответ
Для тестирования асинхронного кода на Python требуются специальные инструменты, так как стандартные test-runner'ы не умеют управлять циклом событий (event loop), необходимым для выполнения async/await функций.
Самый популярный подход — использование библиотеки pytest-asyncio.
1. Написание асинхронного теста с pytest
Тестовая функция должна быть определена с async def и отмечена декоратором @pytest.mark.asyncio. Это указывает pytest-asyncio на необходимость запустить для этого теста event loop.
import pytest
# Функция, которую мы тестируем
async def fetch_data():
# ... какой-то асинхронный вызов
return {"data": 123}
@pytest.mark.asyncio
async def test_fetch_data():
result = await fetch_data()
assert result == {"data": 123}
2. Использование AsyncMock для мокирования
Для имитации асинхронных объектов используется unittest.mock.AsyncMock, так как его можно вызывать через await, в отличие от стандартного Mock.
from unittest.mock import AsyncMock
@pytest.mark.asyncio
async def test_with_mock():
# Создаем мок, который можно 'await'-ить
mock_api_call = AsyncMock(return_value=42)
result = await mock_api_call()
mock_api_call.assert_awaited_once()
assert result == 42
Ключевые моменты:
- Декоратор: Всегда помечайте асинхронные тесты (
@pytest.mark.asyncio). - Моки: Используйте
AsyncMockили асинхронные аналоги из других библиотек. - Фикстуры: Асинхронные фикстуры также должны быть
async defи использовать декоратор@pytest_asyncio.fixture.