Har*_*ddy 3 python subprocess mocking python-2.7
我有一个模块 utils.py,它有这个 run_cmd() 方法
def run_cmd(cmd):
pipe = subprocess.Popen(cmd,
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
print(pipe.communicate())
print(pipe.returncode)
stdout, stderr = [stream.strip() for stream in pipe.communicate()]
output = ' - STDOUT: "%s"' % stdout if len(stdout) > 0 else ''
error = ' - STDERR: "%s"' % stdout if len(stderr) > 0 else ''
logger.debug("Running [{command}] returns: [{rc}]{output}{error}".format(
command=cmd,
rc=pipe.returncode,
output=output,
error=error))
return pipe.returncode, stdout, stderr
Run Code Online (Sandbox Code Playgroud)
我使用模拟和此链接stackoverflow作为参考编写了一个单元测试
@patch('subprocess.Popen')
@patch('utils.logger.debug')
def test_run_cmd(self, mock_popen, mock_log):
cmd = 'mock_command'
mocked_pipe = Mock()
attrs = {'communicate.return_value': ('output', 'error'), 'returncode': 0}
mocked_pipe.configure_mock(**attrs)
mock_popen.return_value = mocked_pipe
log_calls = [call('Running [mock_command] returns: [0]outputerror')]
utils.run_cmd(cmd)
mock_popen.assert_called_once_with(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
mock_log.assert_has_calls(log_calls)
Run Code Online (Sandbox Code Playgroud)
当我运行鼻子测试时,我得到了这个作为输出
stdout, stderr = [stream.strip() for stream in pipe.communicate()]
ValueError: need more than 0 values to unpack
-------------------- >> begin captured stdout << ---------------------
<MagicMock name='Popen().communicate()' id='140197276165008'>
<MagicMock name='Popen().returncode' id='140197276242512'>
--------------------- >> end captured stdout << ----------------------
FAILED (errors=1)
Run Code Online (Sandbox Code Playgroud)
为什么 pipe.communicate() 不打印 ('output', 'error') 或 pipe.returncode 不打印 0,而是它们的模拟方法?哪里出错了?我怎么能解决这个问题?
啊,你的问题已经有了答案。仔细观察,你就会知道为什么。你必须像对logger. 您utils在创建模拟对象时忘记提及。
@patch('utils.subprocess.Popen')
Run Code Online (Sandbox Code Playgroud)
现在,用多个值模拟嵌套函数,我认为您应该查看side_effects和here。
我还没有测试过下面的代码,但我希望它可以工作,或者至少给你一些线索。
mocked_open.return_value.communicate.return_value = ('output', 'error')
mocked_open.return_value.returncode = 0
Run Code Online (Sandbox Code Playgroud)
希望这会有所帮助!