Используйте методы на объекте Mock - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть объект, который используется для получения информации из другого сервиса, который очень прост.Поскольку объект прост и метод инициализации может быть легко исправлен, я подумал, что постараюсь написать свой код, который можно было бы использовать повторно и расширять.Но, увы, я не могу понять, как заставить это работать.Приведенный ниже код довольно хорошо sudo-код и супер упрощен, но он должен понять все.

class SimpleClient:
    def __init__(self):
        pass
    def read(self, key, path='some/path'):
        return value_from_get_on_another_service

У меня тогда есть объект обработчика запросов, который инициализирует клиента через get_client () (см. Ниже)

def get_client():
    return SimpleClient()

Затем метод в обработчике запросов несколько раз использует метод client.read () с различными параметрами (2-й зависит от 1-го).

В моих тестах я думал, что смогу«пропатчить» метод get_client для возврата моего собственного простого объекта, который затем можно будет использовать «регулярно», устранить зависимость от стороннего сервиса и фактически использовать значения, полученные из выполнения метода.Я был разочарован, обнаружив, что это не так просто и чисто.Тестовый образец показан ниже.

class MockClient:
    def __init__(self, addr='someAddr', token='someToken'):
        pass

    def read(self, value, prefix):
        data = {}
        if prefix == 'path/1':
            data = self.p1_lookup(value)
        elif prefix == 'path/2':
            data = self.p2_lookup(value)

        return self.response_wrapper(data)

    def p2_lookup(self, key):
        data = {
        'key1': {
            'sub_key': {"55B3FE7D-9F43-4DD4-9090-9D89330C918A": "Dev2",
                        "7A1C2F4B-E91C-4659-A33E-1B18B0BEE2B3": "Dev"}
        }
    }

    return data.get(key, {})


@mock.patch('a.module.get_client')
def test_authorize_valid_request_no_body(mock_get_client):
    request = RequestMock()
    request.body = None
    handler = RequestHandler(Application(), request=request, logging_level='INFO')
    mock_get_client.return_value = MockClient()
    handler.authorize_request()
    assert handler.verified_headers is None
    assert handler.verified_body is None
    assert handler.user_authenticated is False

Я видел, где можно смоделировать ответы для фактического client.read (), чтобы возвращать несколько значений со списком.Но похоже, что я буду много копировать и вставлять, и мне придется делать одно и то же снова и снова для каждого маленького теста.Простите, если это просто, к сожалению, я только учусь искусству тестирования.Есть ли способ выполнить то, что я пытаюсь сделать?Может быть, есть что-то супер простое, что мне не хватает.Или, может быть, я просто на неправильном пути без веской причины.Помощь?!

1 Ответ

0 голосов
/ 28 ноября 2018

После сна, со свежими глазами, я смог понять это сравнительно быстро благодаря паре других подобных вопросов / ответов, которые я не нашел раньше.Прежде всего, это Python Mock Object с методом, который называется Multiple Times .

Вместо того, чтобы полностью восстанавливать объект модуля, мне нужно позволить mock сделать это для меня, а затем переопределить конкретный метод наэто с атрибутом side_effect.Ниже показано, как выглядит очищенная версия кода.

def read_override(value, prefix):
    lookup_data1 = {"lookup1": {'key1': 'value1'}}
    lookup_data2 = {'some_id': {'akey': {'12345678': 'DEV'}}

    data = {}
    if prefix == 'path1/1a':
        data = lookup_data1.get(value, {})
    elif prefix == 'path2/2a':
        data = lookup_data2.get(value, {})

    return {'data': data}

# Create a true Mock of the entire LookupClient Object
VAULT_MOCK = mock.Mock(spec=LookupClient)

# make the read method work the way I want it to with an "override" of sorts
VAULT_MOCK.read.side_effect = vault_read_override

Тогда тест выглядел просто так ...

@mock.patch('a.module.get_client')
def test_authorize_valid_request_no_body(get_client):
    get_client.return_value = VAULT_MOCK
    request = RequestMock()
    request.body = None
    handler = RequestHandler(Application(), request=request, logging_level='INFO')
    handler.authorize_request()
    assert handler.verified_headers is None
    assert handler.verified_body is None
    assert handler.user_authenticated is False
...