Как я могу предотвратить запуск кода верхнего уровня при импорте? - PullRequest
2 голосов
/ 05 февраля 2020

Я хочу протестировать модуль Python, который, в свою очередь, зависит от другого модуля Python, который, в свою очередь, ведет себя плохо: он не проверяет __name__, но всегда выполняет некоторый код. Этот код обращается к файловой системе и, следовательно, мешает модульному тестированию.

Вот упрощенная версия проблемы, которая просто печатает что-то:

test.py:

from unittest import TestCase
import tested

class MyTest(TestCase):
    def test_one(self, mocked_dep):
        self.assertEqual(1, tested.one())

if __name__ == '__main__':
    import unittest
    unittest.main()

Тестируемый код, test.py:

import dep

def one():
    return 1

Зависимость с плохим поведением, dep.py:

def do_stuff():
    # access file system, open network connection, go to database
    print("I got called!")

do_stuff()

Когда я запускаю это, я вижу напечатанное сообщение.

I got called!
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Как я могу предотвратить do_stuff из запущенного?

Я пытался его смоделировать, но к тому времени, когда мой @patch был оценен с import tested в начале test.py, модуль, вероятно, уже загружен и do_stuff имеет был вызван.

Я также пытался import tested после @patch внутри теста (удаляя import tested в строке 3), но он все еще вызывал do_stuff и печатал его вывод.

from unittest import TestCase
from mock import patch

class MyTest(TestCase):
    @patch("tested.dep.do_stuff")     # <-- too late? still prints
    def test_one(self, mocked_dep):
        import tested                 # <-- moving the import here did not help either
        self.assertEqual(1, tested.one())

Я не могу изменить поведение dep.py, так как от него может зависеть слишком много другого кода.

Как я могу предотвратить вызов do_stuff? Или это единственный вариант для насмешки над функциями, которые я не хочу вызывать do_stuff, в данном случае print?

...