我试图在以下业务代码中模拟 Popen 实例:
process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
output = process.communicate()[0]
if process.returncode != 0:
这是我的测试代码设置:
@mock.patch('subprocess.Popen.returncode')
@mock.patch('subprocess.Popen.communicate')
def testCommandExecutesCommunicate(self, mock_popen_communicate, mock_popen_returncode):
我也尝试过:
@mock.patch('subprocess.Popen.returncode')
@mock.patch('subprocess.Popen.communicate')
def testCommandExecutesCommunicate(self, mock_popen_communicate, mock_popen_returncode):
在这两种情况下,我都会收到 returncode
模拟错误
Error
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/case.py", line 329, in run
testMethod()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mock/mock.py", line 1297, in patched
arg = patching.__enter__()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mock/mock.py", line 1369, in __enter__
original, local = self.get_original()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/mock/mock.py", line 1343, in get_original
"%s does not have the attribute %r" % (target, name)
AttributeError: <class 'subprocess.Popen'> does not have the attribute 'returncode'
我应该如何模拟 Popen?我应该以某种方式模拟 Popen 类吗?或者我通过模拟方法+属性走在正确的轨道上吗?
最佳答案
`AttributeError: does not have the attribute 'returncode'
查看subprocess.py
中的代码,
class Popen():
def __init__(self, ....):
self.returncode = None
属性returncode
由__init__
设置,稍后由communicate()
等更新,类属性returncode
> 不模拟友好并导致错误
why mockp.communicate() mockp.communicate.return_value = '123'
mockp.communicate
或者配合 ()
,与 mockp.communicate = mock.Mock()
相同,一种创建方式用于函数communicate
mock.communicate.return_value = list([2, 3])
是设置mock函数的return_value。
solution: I am not totally happy with the solution, but I tend to think mock the whole class 'Popen()` is the way to go for the unittests.
对于unittest,只需模拟整个类,模拟subprocess.Popen
并设置returncode
和communicate()
并设置return_value
,例如
remove_file.py
def do_cmd(command):
process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
exit_code = process.communicate()[0]
return exit_code
test_remove_file.py
class TestDoCmd(unittest.TestCase):
@mock.patch('remove_file.subprocess.Popen')
def test_do_cmd(self, mockp):
# add function
mockp.returncode.return_value = 'abc'
mockp.communicate()
mockp.communicate.return_value = '123'
file = '/tmp/none.txt'
remove_file.do_cmd('rm -f {}'.format(file))
mockp.assert_called_with('rm -f /tmp/none.txt', shell=True, stdout=-1)
关于 python : mock an attribute or mock the whole class?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51562651/