Как с помощью моков (unittest.mock) протестировать асинхронный контекстный менеджер, не создавая бесконечное количество boilerplate-кода?

MagicMock и AsyncMock уже поддерживают __aenter__ и __aexit__. Настройте возвращаемый при входе объект и подменяйте именно тот протокол, который использует код: фабрика может быть синхронной.

Короткий ответ

Что ответить на собеседовании

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.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее