Тестирование клиента aiohttp с помощью unittest.mock.patch

Я написал простой HTTP-клиент, используя aiohttp, и пытаюсь протестировать его, исправляя aiohttp.ClientSession и aiohttp.ClientResponse. Однако похоже, что декоратор unittest.mock.patch не учитывает мой асинхронный код. На первый взгляд, я бы сказал, что это какое-то несоответствие пространства имен.

Вот минимальный пример:

from aiohttp import ClientSession

async def is_ok(url:str) -> bool:
    async with ClientSession() as session:
        async with session.request("GET", url) as response:
            return (response.status == 200)

Я использую асинхронный декоратор для тестирования, как описано в этом ответе. Итак, вот мой предпринятый тест:

import unittest
from unittest.mock import MagicMock, patch

from aiohttp import ClientResponse

from my.original.module import is_ok

class TestClient(unittest.TestCase):
    @async_test
    @patch("my.original.module.ClientSession", spec=True)
    async def test_client(self, mock_client):
        mock_response = MagicMock(spec=ClientResponse)
        mock_response.status = 200

        async def _mock_request(*args, **kwargs):
            return mock_response

        mock_client.request = mock_response

        status = await is_ok("foo")
        self.assertTrue(status)

Моя сопрограмма is_ok работает нормально, когда она используется, скажем, в __main__, но когда я запускаю тест, она выдает мне ошибку, указывающую, что функция session.request не была имитирована для моего вызова patch. (В частности, он говорит «Не удалось проанализировать имя хоста из URL-адреса« foo »», что должно быть, если оно не было издевательским.)

Я не могу избежать этого поведения. Я пытался:

  • Импорт is_ok после завершения насмешек.
  • Различные комбинации назначения макетов для mock_client и mock_client.__aenter__, установки mock_client.request для MagicMock(return_value=mock_response) или использования mock_client().request и т. д.
  • Написание макета ClientSession с определенными методами __aenter__ и __aexit__ и использование его в аргументе new для patch.

Ни один из них, кажется, не имеет значения. Если я помещаю утверждения в is_ok, чтобы проверить, что ClientSession является экземпляром MagicMock, то эти утверждения терпят неудачу, когда я запускаю тест (как, опять же, если код не исправлен). Это приводит меня к моей теории несоответствия пространств имен: то есть цикл событий выполняется в другом пространстве имен, на которое нацелено patch.

Либо так, либо я делаю что-то глупое!


person Xophmeister    schedule 27.09.2017    source источник


Ответы (1)


Насмешка над ClientSession не рекомендуется.

Рекомендуемый способ — создание поддельного сервера и отправка ему настоящих запросов.

Взгляните на https://github.com/aio-libs/aiohttp/blob/master/examples/fake_server.py.

person Andrew Svetlov    schedule 28.09.2017
comment
Это похоже на использование тестовой базы данных вместо того, чтобы издеваться над всеми выполнениями SQL. - person Andrew Svetlov; 28.09.2017
comment
Ага, а-ля интеграционное тестирование. Понятно и необходимо, но, возможно, излишне, если вы просто хотите протестировать поток управления. - person Xophmeister; 28.09.2017
comment
Однако вы можете взглянуть на github.com/pnuckowski/aioresponses. - person Andrew Svetlov; 28.09.2017
comment
Идеально :) Спасибо - person Xophmeister; 28.09.2017
comment
Я не думаю, что это ответ на вопрос - person HXH; 04.12.2017
comment
Вы вправе не соглашаться, конечно. Как автор библиотеки aiohttp, я просто делюсь своим видением правильного использования библиотеки. - person Andrew Svetlov; 04.12.2017
comment
Ответы @AndrewSvetlov, кажется, высмеивают все запросы. приведет к сбою получения или публикации других мест - person carton.swing; 06.09.2018
comment
Да, это тоже меня беспокоит - person Andrew Svetlov; 06.09.2018
comment
Я так понимаю, что для тестирования ClientSession лучше всего использовать поддельный сервер. Однако для тестирования кода, который просто использует ClientSession, было бы здорово иметь решение, которое работает без поддельного сервера. Жаль, что aioresponses кажется скорее обезьяньим патчем, чем насмешкой, и поэтому может иметь странные побочные эффекты. Возможно, сработает сочетание имитации исправления ClientSession с подклассом и обезьяньего исправления подкласса? - person gelonida; 01.05.2020