ModuleNotFoundError, но только когда над ним издеваются

#python #unit-testing #mocking

Вопрос:

У меня есть вызванный пакет my_package с одним модулем под названием my_module :

 $ tree my_package/
my_package/
├── __init__.py
├── my_module.py
├── my_module.py~
└── __pycache__
    ├── __init__.cpython-36.pyc
    └── my_module.cpython-36.pyc
 

my_module имеет функцию, называемую compute_something :

 $ cat my_package/my_module.py
def compute_something():
    return 0
 

Я пытаюсь высмеять эту функцию в целях модульного тестирования:

 $ cat mocks.py
import mock

from my_package import my_module

def unmocked():
    print(my_module.compute_something())

@mock.patch('my_module.compute_something')
def mocked(mock_compute_something):
    mock_compute_something.return_value = 1
    print(my_module.compute_something())

unmocked()
mocked()
$ python mocks.py
0
Traceback (most recent call last):
  File "mocks.py", line 14, in <module>
    mocked()
  File "/home/pcoccoli/.pyenv/versions/3.6.8/lib/python3.6/site-packages/mock/mock.py", line 1345, in patched
    keywargs) as (newargs, newkeywargs):
  File "/home/pcoccoli/.pyenv/versions/3.6.8/lib/python3.6/contextlib.py", line 81, in __enter__
    return next(self.gen)
  File "/home/pcoccoli/.pyenv/versions/3.6.8/lib/python3.6/site-packages/mock/mock.py", line 1325, in decoration_helper
    arg = exit_stack.enter_context(patching)
  File "/home/pcoccoli/.pyenv/versions/3.6.8/lib/python3.6/contextlib.py", line 330, in enter_context
    result = _cm_type.__enter__(cm)
  File "/home/pcoccoli/.pyenv/versions/3.6.8/lib/python3.6/site-packages/mock/mock.py", line 1398, in __enter__
    self.target = self.getter()
  File "/home/pcoccoli/.pyenv/versions/3.6.8/lib/python3.6/site-packages/mock/mock.py", line 1573, in <lambda>
    getter = lambda: _importer(target)
  File "/home/pcoccoli/.pyenv/versions/3.6.8/lib/python3.6/site-packages/mock/mock.py", line 1245, in _importer
    thing = __import__(import_path)
ModuleNotFoundError: No module named 'my_module'
 

Как вы можете видеть, my_module существует и находится просто отлично (я вызываю его из unmocked функции, и вы можете видеть его вывод), если я не попытаюсь mock.patch это сделать. Я не понимаю, почему это так.

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

1. Я думаю, никто не хочет, чтобы над ним насмехались.

2. Я предполагаю, что декораторы вызывают эту функцию из другого файла, где my_module не распознан. Что происходит, когда вы помещаете инструкцию import внутри издевательской функции?

3. Не совсем понимаю, что ты имеешь в виду. Декоратор не вызывает функцию — он должен исправить ее в текущем пространстве имен.

4. python @mock.patch('my_module.compute_something') здесь метод path из класса mock вызывается в другом сеансе со строковой ссылкой на my_module.compute_something. Этот другой сеанс понятия не имеет, что или где это.

5. не могли бы вы попытаться перейти from my_package import my_module на import my_package

Ответ №1:

После перечитывания https://docs.python.org/3/library/unittest.mock.html#where-to-patch Я вижу, что это должно быть:

 @mock.patch('mocks.my_module.compute_something')
 

Это потому, что я импортировал my_module в mocks.py . В моем коде в вопросе отсутствует ведущее «издевается». в target .

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

1. Разве это дурной тон-отвечать на свой собственный вопрос?