[英]python unit testing mocking Popen and Popen.communicate
我正在尝试编写一个执行子流程调用的python unittest,所以我想模拟该调用。
我已经经历了这些SO问题(无济于事):
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()
运行单元测试时,我得到:
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()
正如jonrsharpe已经提到的, with Popen(...) as process
使用Popen
实例作为上下文管理器,它调用__enter__
方法并分配它的值process
。
jonsharpe的解决方案使用了mock
return_value
魔术,效果很好。 但是您也可以实现一个上下文管理器,并将模拟逻辑包装在其中:
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.txt
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.