Как мне высмеять иерархию несуществующих модулей?

#mocking #pytest #python-unittest

#python #издевательство #python-макет

Вопрос:

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

Вот небольшой пример. Функциональность, которую я хочу протестировать, помещается в файл с именем actual.py :

 actual.py:


def coolfunc():
  from level1.level2.level3_1 import thing1
  from level1.level2.level3_2 import thing2
  do_something(thing1)
  do_something_else(thing2)
 

В моем наборе тестов у меня уже есть все, что мне нужно: у меня есть thing1_mock и thing2_mock . Также у меня есть функция тестирования. Что мне нужно, так это добавить level1.level2... в текущую систему модулей. Вот так:

 tests.py

import sys
import actual

class SomeTestCase(TestCase):
  thing1_mock = mock1()
  thing2_mock = mock2()

  def setUp(self):
    sys.modules['level1'] = what should I do here?

  @patch('level1.level2.level3_1.thing1', thing1_mock)
  @patch('level1.level2.level3_1.thing1', thing2_mock)
  def test_some_case(self):
    actual.coolfunc()
 

Я знаю, что я могу sys.modules['level1'] заменить объект, содержащий другой объект, и так далее. Но мне кажется, что для меня это слишком много кода. Я предполагаю, что должно быть гораздо более простое и красивое решение. Я просто не могу его найти.

Ответ №1:

Итак, никто не помог мне с моей проблемой, и я решил решить ее самостоятельно. Вот вызываемая микро-библиотека surrogate , которая позволяет создавать заглушки для несуществующих модулей.

Lib можно использовать mock примерно так:

 from surrogate import surrogate
from mock import patch

@surrogate('this.module.doesnt.exist')
@patch('this.module.doesnt.exist', whatever)
def test_something():
    from this.module.doesnt import exist
    do_something()
 

Сначала @surrogate декоратор создает заглушки для несуществующих модулей, затем @patch декоратор может их изменять. Точно так же @patch , @surrogate декораторы могут использоваться «во множественном числе», тем самым ограничивая более одного пути к модулю. Все заглушки существуют только во время жизни оформленной функции.

Если кто-нибудь воспользуется этой библиотекой, это было бы здорово 🙂

Комментарии:

1. Почему бы вам не создать библиотеку pip? это потрясающе!

Ответ №2:

Вы можете использовать параметр «create» в методе patch(), который принудительно создаст атрибут, если он не существует.

Комментарии:

1. Это не работает для модулей, о которых идет речь.