Python: Имитируйте модуль, не импортируя его и не требуя его существования

Я начинаю использовать фиктивную библиотеку python для тестирования. Я хочу имитировать модуль, который импортируется в пространстве имен тестируемого модуля, не импортируя его или не требуя, чтобы он существовал первым (т.е. бросил ImportError).

Предположим, существует следующий код:

foo.py

 import helpers
 def foo_func():
    return helpers.helper_func()

Цель состоит в том, чтобы протестировать foo_func (), когда 'helpers.py' нигде не существует, и если он существует, действовать так, как будто его нет.

Сначала попробуйте использовать супер классный декоратор @patch:

from mock import patch, sentinel
import foo
@patch("foo.helpers")
def foo_test(mock):
    mock.helper_func.return_value = sentinel.foobar
    assert foo.foo_func() == sentinel.foobar

Это работает, если модуль "помощники" можно импортировать. Если это не так не существует, я получаю ImportError.

Следующая попытка с патчем без декоратора:

from mock import patch, sentinel, Mock
import foo
helpers_mock = patch("foo.helpers")
helpers_mock.start()

def foo_test():
    helpers_mock.helper_func = Mock('helper_func')
    helpers_mock.helper_func.return_value = sentinel.foobar
    assert foo.foo_func() == sentinel.foobar

Опять же, это не работает, если "помощники" отсутствуют ... и, если они существуют, утверждение не выполняется. Не совсем уверен, почему это происходит.

Третья попытка, текущее решение:

import sys
helpers_mock = Mock(name="helpers_mock", spec=['helper_func'])
helpers_mock.__name__ = 'helpers'
sys.modules['helpers'] = helpers_mock
import foo
def foo_test():
    helpers_mock.helper_func.return_value = sentinel.foobar
    assert foo.foo_func() == sentinel.foobar

Этот тест проходит независимо от того, существует ли "helpers.py".

Это лучший способ достичь этой цели? Является ли используемая мной имитационная библиотека альтернативой этому? Как еще я могу это сделать?

12
задан Kyle Gibson 20 December 2018 в 16:39
поделиться