Тестирование обработки ошибок в программе с использованием Swagger Codegen API в Python - PullRequest
0 голосов
/ 18 января 2019

Это может быть просто, но насмешка в целом действительно смущает меня, поэтому я не уверен, что делать.

В настоящее время у меня есть внешний API, с которым я работаю, сгенерированный библиотекой Swagger Codegen. У меня нет оригинального шаблона, использованного для его создания, но у меня есть библиотека, похожая на пример swashger * petshop . Я пытаюсь протестировать мой код, взаимодействующий с API, но у меня возникают проблемы с тестированием того, что происходит, когда внешний API вызывает исключение.

В настоящее время у меня есть что-то подобное для моих тестов:

mock_api = mocker.patch('<swagger_api>.ApiClient.call_api')
mock_api.side_effect = [ApiException(status=429), mocker.DEFAULT]

И мой след:

/home/rob/.pyenv/versions/3.6.6/lib/python3.6/unittest/mock.py:939: in __call__
    return _mock_self._mock_call(*args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

_mock_self = <MagicMock name='call_api' id='140060372397864'>
args = ('/companies', 'GET', {}, [('next_page', <MagicMock name='call_api().next_page' id='140060365572248'>)], {'Accept': 'application/json'})
kwargs = {'_async': None, '_preload_content': True, '_request_timeout': None, '_return_http_data_only': True, ...}
self = <MagicMock name='call_api' id='140060372397864'>, _new_name = '', _new_parent = None
_call = call('/companies', 'GET', {}, [('next_page', <MagicMock name='call_api().next_page' id='140060365572248'>)], {'Accept'...tings=['ApiKeyAuth'], body=None, collection_formats={}, files={}, post_params=[], response_type='ApiResponseCompanies')
seen = set(), skip_next_dot = False, do_method_calls = False, name = 'call_api'

    def _mock_call(_mock_self, *args, **kwargs):
        self = _mock_self
        self.called = True
        self.call_count += 1
        _new_name = self._mock_new_name
        _new_parent = self._mock_new_parent

        _call = _Call((args, kwargs), two=True)
        self.call_args = _call
        self.call_args_list.append(_call)
        self.mock_calls.append(_Call(('', args, kwargs)))

        seen = set()
        skip_next_dot = _new_name == '()'
        do_method_calls = self._mock_parent is not None
        name = self._mock_name
        while _new_parent is not None:
            this_mock_call = _Call((_new_name, args, kwargs))
            if _new_parent._mock_new_name:
                dot = '.'
                if skip_next_dot:
                    dot = ''

                skip_next_dot = False
                if _new_parent._mock_new_name == '()':
                    skip_next_dot = True

                _new_name = _new_parent._mock_new_name + dot + _new_name

            if do_method_calls:
                if _new_name == name:
                    this_method_call = this_mock_call
                else:
                    this_method_call = _Call((name, args, kwargs))
                _new_parent.method_calls.append(this_method_call)

                do_method_calls = _new_parent._mock_parent is not None
                if do_method_calls:
                    name = _new_parent._mock_name + '.' + name

            _new_parent.mock_calls.append(this_mock_call)
            _new_parent = _new_parent._mock_new_parent

            # use ids here so as not to call __hash__ on the mocks
            _new_parent_id = id(_new_parent)
            if _new_parent_id in seen:
                break
            seen.add(_new_parent_id)

        ret_val = DEFAULT
        effect = self.side_effect
        if effect is not None:
            if _is_exception(effect):
                raise effect

            if not _callable(effect):
>               result = next(effect)
E               StopIteration

/home/rob/.pyenv/versions/3.6.6/lib/python3.6/unittest/mock.py:998: StopIteration

Я не думаю, что это специфично для API, который я использую, поэтому я пропустил эти части трассировки и кода для конфиденциальности.

Я бы хотел, чтобы это произошло:

  • Код вызова API
  • При первом вызове API, , но возникает исключение. Я предпочел бы, чтобы мне не пришлось макетировать весь ответ на вызов API.
  • Код для обработки исключения и повторных попыток вызова API снова
  • На этот раз API вызывает внешний API и возвращает ответ.

Обратите внимание, что я делаю это для нескольких вызовов API, поэтому мои тесты параметризованы с помощью вызываемых элементов, поэтому на самом деле невозможно смоделировать код в более ранней точке цикла API Swagger. Удаление параметризованных тестов является одной из возможностей, но я бы предпочел другой вариант.

Если уже есть библиотека, которая делает это, это было бы идеально.

...