assert_called_with исправленной функции - PullRequest
0 голосов
/ 19 марта 2019

Я пытаюсь подтвердить ввод пропатченного запроса request.get (), который заключен в другую функцию.

def get_data(*args):
    # logic to define url, based on '*args'
    url = 'some_url?arg1&arg3'

    # call I want to patch and assert the url of
    response = request.get(url)

    # process response
    stuff = 'processed_response'
    return stuff

тестовый скрипт:

def mock_response_200(url):
    response = mock.MagicMock()
    response.status_code = 200
    response.json = mock.Mock(return_value={  
        0: {'key1': 'value1', 'key2': 'value2'}
    })
    return response

@mock.patch('request.get', new=mock_response_200)
def test_get_data():
    arg1 = 'arg1'
    arg2 = None
    arg3 = 'arg3'

    stuff = get_data(arg1, arg2, arg3)
    # <assert input arguments of patched function here>

Как мне подтвердить URL, который был передан mocked_response_200? mocked_response_200 не известен в test_get_data.
Я проверил другие сообщения здесь Это близко , но в ответе используется другой метод исправления. Любая помощь будет принята с благодарностью.

Ответы [ 3 ]

1 голос
/ 19 марта 2019

Вы исправляете неизвестный объект get в модуле request. У вас, вероятно, нет такого модуля или объекта.

Вам необходимо обратиться к request объекту в тестируемом модуле . Если get_data живет в модуле views, то вам нужно установить патч views.request.get здесь:

@mock.patch('views.request.get', new=mock_response_200)

Из mock.patch() документации :

target должен быть строкой в ​​форме 'package.module.ClassName'. Цель импортируется, а указанный объект заменяется новым, поэтому цель должна импортироваться из среды, из которой вы вызываете patch(). Цель импортируется при выполнении декорированной функции, а не во время декорации.

Однако я бы не использовал здесь функцию . Просто дайте mock-патчу для вас метод get(), затем настройте этот фиктивный объект. Конечно, вы можете передать это вспомогательной функции:

def config_response_200_mock(request_get):
    response = request_get.return_value
    response.status_code = 200
    response.json.return_value = {  
        0: {'key1': 'value1', 'key2': 'value2'}
    }
    return response

@mock.patch('views.request.get')
def test_get_data(request_get):
    response_mock = config_response_200_mock(request_get)

    arg1 = 'arg1'
    arg2 = None
    arg3 = 'arg3'

    stuff = get_data(arg1, arg2, arg3)

Вы также можете создать магический фиктивный объект в такой функции, а затем передать функцию в new_callable on mock.patch():

def response_200_mock():
    get_mock = mock.MagicMock()
    response = get_mock.return_value
    response.status_code = 200
    response.json.return_value = {  
        0: {'key1': 'value1', 'key2': 'value2'}
    }
    return get_mock

@mock.patch('views.request.get', new_callable=response_200_mock)
def test_get_data(request_get):
    arg1 = 'arg1'
    arg2 = None
    arg3 = 'arg3'

    stuff = get_data(arg1, arg2, arg3)

В любом случае, объект, используемый для исправления request.get, передается в test_get_data в качестве аргумента.

Демонстрация любого из подходов (использование patch в качестве менеджера контекста вместо декоратора, но принцип тот же:

>>> def config_response_200_mock(request_get):
...     response = request_get.return_value
...     response.status_code = 200
...     response.json.return_value = {
...         0: {'key1': 'value1', 'key2': 'value2'}
...     }
...     return response
...
>>> with mock.patch('__main__.request.get') as request_get:
...     response_mock = config_response_200_mock(request_get)
...     arg1 = 'arg1'
...     arg2 = None
...     arg3 = 'arg3'
...     stuff = get_data(arg1, arg2, arg3)
...
>>> stuff
'processed_response'
>>> response_mock.json()
{0: {'key1': 'value1', 'key2': 'value2'}}
>>> request_get.mock_calls
[call('some_url?arg1&arg3')]
>>> def response_200_mock():
...     get_mock = mock.MagicMock()
...     response = get_mock.return_value
...     response.status_code = 200
...     response.json.return_value = {
...         0: {'key1': 'value1', 'key2': 'value2'}
...     }
...     return get_mock
...
>>> with mock.patch('__main__.request.get', new_callable=response_200_mock) as request_get:
...     arg1 = 'arg1'
...     arg2 = None
...     arg3 = 'arg3'
...     stuff = get_data(arg1, arg2, arg3)
...
>>> stuff
'processed_response'
>>> request_get.return_value.json()
{0: {'key1': 'value1', 'key2': 'value2'}}
>>> request_get.mock_calls
[call('some_url?arg1&arg3')]
0 голосов
/ 19 марта 2019

Прежде всего, большое спасибо @ Ja8zyjits и @Martijn Pieters за помощь.
Решение, которое сработало для меня, выглядит следующим образом:

@mock.patch('request.get', side_effect=mock_response_200)
def test_get_data(mock_get):
    arg1 = 'arg1'
    arg2 = None
    arg3 = 'arg3'
    expected_url = 'some_url?arg1&arg3'

    stuff = get_data(arg1, arg2, arg3)

    mock_get.assert_called_with(url)

Я не могу сказать, что полностью понимаю взаимодействие между передачей mock_response_200 как 'side_effect' и передачей mock_get в test_get_data. Но используя эту комбинацию, я смог как подтвердить ввод пропатченного request.get, так и вернуть желаемый ответ, чтобы избежать появления ошибок во время обработки ответа.

редактировать: форматирование кода

0 голосов
/ 19 марта 2019

Unittest - это тестирование одного базового компонента за раз. Таким образом, каждый другой компонент, вызываемый внутри, должен быть протестирован в других тестах.

Если вы хотите только утверждать, что url было передано правильно, то я бы предложил не использовать new ключевое слово

@mock.patch('module.process_response')
@mock.patch('module.request.get')
def test_get_data(mock_get, mock_process_response):
    arg1 = 'arg1'
    arg2 = None
    arg3 = 'arg3'
    url = "what ever url"

    stuff = get_data(arg1, arg2, arg3)
    mock_get.assert_called_with(url)

Это поможет вам определить, правильно ли он был вызван. В более поздних тестах используйте ключевое слово new, чтобы проверить, был ли возвращенный ответ обработан_производителем.

mock_process_response является объектом MagicMock и будет препятствовать вызову process_response и, следовательно, не потребует mock_get для определения json или status_code для определения.

правки: добавлен макет для process_response.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...