Python mock.patch не исправляет правильный импорт

Код

def test_get_network_info(self):
    with open(dirname(abspath(__file__)) + '/files/fake_network_info.txt', 'r') as mock_network_info:
        with patch('subprocess.check_output', Mock(return_value=mock_network_info.read())):
            self.assertEqual('192.168.1.100', get_network_info()[0])
            self.assertEqual('255.255.255.0', get_network_info()[1])
            self.assertEqual('192.168.1.0', get_network_info()[2])

Ошибка

======================================================================
ERROR: test_get_network_info (tests.test_tools.ToolsTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tim/Documents/overseer/app/tests/test_tools.py", line 21, in test_get_network_info
    with patch('subprocess.check_output', Mock(return_value=mock_network_info.read())):
  File "/usr/local/lib/python2.7/dist-packages/mock.py", line 1268, in __enter__
    original, local = self.get_original()
  File "/usr/local/lib/python2.7/dist-packages/mock.py", line 1242, in get_original
    "%s does not have the attribute %r" % (target, name)
AttributeError: <module 'subprocess' from '/usr/local/lib/python2.7/dist-packages/twill/other_packages/subprocess.pyc'> does not have the attribute 'check_output'

что я понимаю

Насколько я понимаю, проблема заключается в том, что mock пытается имитировать модуль subprocess twill вместо модуля python.

Вопросы

  1. Я делаю что-то неправильно ?

  2. Как я могу указать, что я хочу пропатчить модуль python subprocess, а не модуль саржи? (которые могли быть импортированы ранее в тестовом наборе)**

  3. Есть ли другой способ исправить модуль subprocess?

Что я пробовал

  • Я пробовал with patch('tools.subprocess.check_output', ...

Не работает.

  • Я устал использовать декоратор...

Тоже не работает

  • Надоело патчить напрямую subprocess модуль subprocess.check_output = Mock( ...

Работает, но это нехорошо, так как не отменяет исправления.

Еще немного информации

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

Вот версия подпроцесса twill, которая выглядит так был скопирован из старой версии Python. У него нет функции check_output, поэтому тест не проходит.

Пакет Twill входит в состав плагина Flask-Testing, который я широко использую. Я отправил задачу на github здесь.

Я надеюсь, что кто-нибудь из прекрасного сообщества Python сможет помочь. :)


person Timothée Jeannin    schedule 22.12.2013    source источник
comment
Просмотрел исходники саржи, а тут ужас: sys.path.append(extensions) и прочая подобная каша. Модули никогда не должны касаться пути, за исключением случаев, когда изменение пути действительно является частью их функции. Я думаю, что автор не понял, как правильно что-то обработать, и пропатчил путь, и теперь вы застряли в конфликте (вы также не сможете правильно использовать подпроцесс, это не проблема, связанная с mock). Попробуйте отойти от саржи, как я вижу на гитхабе она не обновлялась с пяти лет.   -  person vincent    schedule 23.12.2013


Ответы (1)


См. мой комментарий там, из-за плохой практики в сарже, правильным способом было бы либо исправить саржу, что может потребовать некоторой работы, либо перейти к чему-то другому, но поскольку теперь вы сильно зависите от Flask-Testing, это не тоже дешевый ход.

Так что это оставляет нас с грязным трюком: убедитесь, что import subprocess в любом месте, прежде чем саржа будет импортирована. Внутри это добавит ссылку на правый модуль subprocess в sys.modules. Как только модуль загружен, все последующие import больше не будут искать в sys.path, а просто будут использовать ссылку, уже кэшированную в sys.modules.

К сожалению, это, возможно, не конец проблемы. Очевидно, twill по какой-то причине использует исправленную версию подпроцесса; и эти патчи не будут доступны для него, так как вместо них будет загружен обычный встроенный подпроцесс. Очень вероятно, что он выйдет из строя или поведет себя неожиданным образом. Если это так, что ж... вернемся к предложениям выше.

person vincent    schedule 23.12.2013