我有一个测试方法,如下所示:
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
我正在尝试使用unittest.TestCase
在mock
测试方法中测试其对Popen的调用及其对日志记录函数的调用:
@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作为记录器对象,但我遇到了第一个问题。
答案 0 :(得分:2)
我认为主要问题来自你的补丁对象:
@mock.patch.object(subprocess.Popen, 'communicate', autospec=True)
奇怪的是,似乎正在创建的模拟类型是:
<class 'unittest.mock.NonCallableMagicMock'>
这是我之前第一次遇到NonCallableMagicMock
类型,但查看我在此找到的最少信息,文档指定this:
为我举起旗帜的部分在这里:
除了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
创建了我们的模拟对象。从那里开始,其他一切都与你正在做的事情完全一致。