import pytest
import asyncio
@pytest.mark.asyncio
async def test_async_function():
async def my_async_func():
await asyncio.sleep(0.1)
return True
result = await my_async_func()
assert result == True
Для тестирования асинхронных функций с помощью pytest
необходимо использовать библиотеку pytest-asyncio
. Она предоставляет поддержку асинхронных тестов, позволяя pytest
правильно обрабатывать корутины.
Установка pytest-asyncio
:
pip install pytest-asyncio
Основные моменты использования:
async
.
import pytest
async def my_async_function():
return "Hello, async world!"
@pytest.mark.asyncio
async def test_my_async_function():
result = await my_async_function()
assert result == "Hello, async world!"
@pytest.mark.asyncio
: Этот декоратор помечает функцию как асинхронный тест. Некоторые версии pytest-asyncio
требуют его явного указания, хотя в современных версиях он часто не является обязательным и pytest
автоматически определяет асинхронные тесты. Лучше его использовать для явности и совместимости.
pytest
: Фикстуры могут быть асинхронными. Это позволяет выполнять асинхронные операции (например, подключение к асинхронной базе данных) до и после выполнения тестов.
import pytest
import asyncio
@pytest.fixture(scope="session")
async def async_db_connection():
# Асинхронное подключение к базе данных
print("Connecting to async database...")
await asyncio.sleep(0.1) # Имитация асинхронной операции
connection = "Async DB Connection"
yield connection
# Асинхронное закрытие соединения
print("Closing async database connection...")
await asyncio.sleep(0.1) # Имитация асинхронной операции
@pytest.mark.asyncio
async def test_using_async_fixture(async_db_connection):
assert async_db_connection == "Async DB Connection"
print("Test running with async connection")
asyncio.run()
(в редких случаях): В большинстве случаев pytest-asyncio
сам управляет event loop. Однако, если требуется выполнение синхронного кода, который вызывает асинхронные функции, можно использовать asyncio.run()
. Важно понимать, что это обычно не требуется внутри тестов, а скорее в коде, который тестируется.
import asyncio
import pytest
async def async_task(value):
await asyncio.sleep(0.1)
return value * 2
def sync_function_calling_async(value):
# ВНИМАНИЕ: Использование asyncio.run() в тестах обычно не рекомендуется
# Предпочтительнее, чтобы все тесты были асинхронными
return asyncio.run(async_task(value))
@pytest.mark.asyncio
async def test_async_task():
result = await async_task(5)
assert result == 10
def test_sync_function_calling_async(): # Обычный синхронный тест
result = sync_function_calling_async(3)
assert result == 6
Важное замечание: Настоятельно рекомендуется избегать использования asyncio.run()
внутри тестов. Лучше сделать все тесты асинхронными, чтобы pytest-asyncio
мог корректно управлять event loop.
Пример полного тестового файла (test_async.py
):
import pytest
import asyncio
async def fetch_data(url):
await asyncio.sleep(0.01) # Имитация задержки сети
return f"Data from {url}"
@pytest.mark.asyncio
async def test_fetch_data():
url = "https://example.com"
data = await fetch_data(url)
assert data == f"Data from {url}"
@pytest.fixture
async def async_setup():
print("Setting up async test environment...")
await asyncio.sleep(0.01)
yield
print("Tearing down async test environment...")
await asyncio.sleep(0.01)
@pytest.mark.asyncio
async def test_with_async_setup(async_setup):
print("Running test with async setup")
assert True # Просто пример assert
Запуск тестов:
pytest test_async.py
Преимущества использования pytest-asyncio
:
pytest
.