Макетировать метод экземпляра с определенным возвращаемым значением?
У меня есть тестируемый метод, который выглядит так:
def execute_update(self):
"""Execute an update."""
p = subprocess.Popen(['command'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
try:
stdout, stderr = p.communicate()
if p.returncode == 0:
# successful update, notify
self.logger.info("Successfully updated.")
else:
# failed update, notify
self.logger.error("Unable to update (code {returncode}):\n{output}".format(
returncode=p.returncode, output=stdout))
except KeyboardInterrupt as e:
# terminate the process
p.terminate()
raise e
Я пытаюсь проверить его вызов Popen и вызов функций регистрации в unittest.TestCase
метод испытания с mock
:
@mock.patch.object(subprocess.Popen, 'communicate', autospec=True)
@mock.patch('updateservice.subprocess.Popen', autospec=True)
def test_fetch_metadata(self, mock_popen, mock_communicate):
"""Test that we can fetch metadata correctly."""
mock_communicate.return_value = ("OUT", "ERR")
mock_popen.returncode = 0
self.reference.execute_update()
# other asserts
Последняя строка терпит неудачу с:
stdout, stderr = p.communicate()
ValueError: need more than 0 values to unpack
Что я делаю неправильно? У меня есть следующие требования:
- Проверьте, что конструктор
subprocess.Popen
был вызван с правильными значениями. - Проверьте, что вызовы регистрации выполняются с выходным кодом и кодом возврата от процесса.
Номер два достаточно прост, я просто внедряю MagicMock в качестве объекта регистрации, но у меня проблемы с номером один.
1 ответ
Я думаю, что основная проблема исходит от вашего патча здесь:
@mock.patch.object(subprocess.Popen, 'communicate', autospec=True)
Как ни странно, создается впечатление, что тип создаваемого макета:
<class 'unittest.mock.NonCallableMagicMock'>
Это первый раз, когда я столкнулся с NonCallableMagicMock
введите ранее, но, глядя на минимальную информацию, которую я нашел по этому вопросу, документы определяют это:
Часть, которая поднимает флаг для меня, находится здесь:
за исключением return_value и side_effect, которые не имеют никакого значения для не вызываемого макета.
Это потребовало бы дальнейшего исследования, чтобы определить, что именно это означает. Принимая это во внимание, и, может быть, вы уже попробовали это, следующее изменение в вашем unittest дает успешные результаты насмешки:
@mock.patch('server.upd.subprocess.Popen', autospec=True)
def test_fetch_metadata(self, mock_popen):
"""Test that we can fetch metadata correctly."""
mock_popen.return_value = Mock()
mock_popen_obj = mock_popen.return_value
mock_popen_obj.communicate.return_value = ("OUT", "ERR")
mock_popen_obj.returncode = 0
self.reference.execute_update()
Итак, как вы можете видеть, мы в значительной степени создаем наш фиктивный объект в соответствии с mock_popen.return_value
, Оттуда все остальное в значительной степени соответствует тому, что вы делали.