我正在尝试编写一个执行子进程调用的python,所以我想模拟这个调用。
我已经讨论过这些问题了(但没有结果):
benchmark.py
from subprocess import Popen, PIPE, STDOUT
def some_func():
with Popen(some_list, stdout=PIPE, stderr=STDOUT) as process:
stdout, stderr = process.communicate(timeout=timeout)test.py
import mock
@mock.patch('benchmark.Popen.communicate')
@mock.patch('benchmark.Popen')
def test_some_func(self, mock_popen, mock_comm):
mock_popen.return_value = 0
mock_comm.return_value = ('output', 'error')
foo = benchmark.some_func()当运行unittest时,我得到:
stdout, stderr = process.communicate(timeout=timeout)
ValueError: not enough values to unpack (expected 2, got 0)看起来我没有正确地模拟communicate的返回值;我做错了什么?
解决方案
我接受了这些评论,并提出了解决以下问题的答案:
test.py
import mock
@mock.patch('benchmark.Popen')
def test_some_func(self, mock_popen):
process = mock_popen.return_value.__enter__.return_value
process.returncode = 0
process.communicate.return_value = (b'some output', b'some error')
foo = benchmark.some_func()发布于 2018-12-15 13:42:31
正如jonrsharpe所提到的,with Popen(...) as process使用Popen实例作为上下文管理器,它调用__enter__方法并将其值分配给process。
jonsharpe的解决方案使用了return_value魔术的mock,它工作得很好。但是,您也可以实现上下文管理器,并在其中包装模拟逻辑:
import mock
import subprocess
class MockedPopen:
def __init__(self, args, **kwargs):
self.args = args
self.returncode = 0
def __enter__(self):
return self
def __exit__(self, exc_type, value, traceback):
pass
def communicate(self, input=None, timeout=None):
if self.args[0] == 'ls':
stdout = '\n'.join(['hello.txt', 'world.txt'])
stderr = ''
self.returncode = 0
else:
stdout = ''
stderr = 'unknown command'
self.returncode = 1
return stdout, stderr
@mock.patch('subprocess.Popen', MockedPopen)
def foo():
with subprocess.Popen(['ls']) as proc:
stdout, stderr = proc.communicate()
print(stdout, stderr)
foo()输出:
hello.txt
world.txthttps://stackoverflow.com/questions/53784239
复制相似问题