MagicMock и AsyncMock уже поддерживают aenter и aexit. Настройте возвращаемый при входе объект и подменяйте именно тот протокол, который использует код: фабрика может быть синхронной.
Как с помощью моков (unittest.mock) протестировать асинхронный контекстный менеджер, не создавая бесконечное количество boilerplate-кода?
MagicMock и AsyncMock уже поддерживают __aenter__ и __aexit__. Настройте возвращаемый при входе объект и подменяйте именно тот протокол, который использует код: фабрика может быть синхронной.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
MagicMock и AsyncMock уже поддерживают aenter и aexit. Настройте возвращаемый при входе объект и подменяйте именно тот протокол, который использует код: фабрика может быть синхронной.
Пример для синхронной фабрики, возвращающей асинхронный контекстный менеджер:
from unittest import IsolatedAsyncioTestCase
from unittest.mock import MagicMock, AsyncMock
async def load(factory):
async with factory() as client:
return await client.fetch()
class LoadTest(IsolatedAsyncioTestCase):
async def test_load(self):
factory = MagicMock()
client = MagicMock()
client.fetch = AsyncMock(return_value={"ok": True})
manager = factory.return_value
manager.__aenter__.return_value = client
manager.__aexit__.return_value = False
self.assertEqual(await load(factory), {"ok": True})
manager.__aenter__.assert_awaited_once()
client.fetch.assert_awaited_once()
manager.__aexit__.assert_awaited_once()
Повторяющуюся настройку вынесите в небольшую fixture. В реальном тесте полезно задать spec, чтобы mock не скрывал опечатки интерфейса.
Источник: docs.python.org.