编写测试用例来处理成功和失败的python子进程调用,我需要捕获subprocess.call
返回代码。
使用python unittest.mock module
,是否可以修补subprocess.call
函数并捕获其实际系统退出代码?
考虑使用以下代码的外部库:
## <somemodule.py> file
import subprocess
def run_hook(cmd):
# ...
subprocess.call(cmd, shell=True)
sum_one = 1+1
return sum_one
我无法修改函数run_hook
。它不是我的代码的一部分。但是,事实是subprocess.call
在其他陈述中被调用。
这里我们有一段代码返回强制系统退出错误代码1:
## <somemodule.py> tests file
import subprocess
from somemodule import run_hook
try:
from unittest.mock import patch
except ImportError:
from mock import patch
@patch("subprocess.call", side_effect=subprocess.call)
def test_run_hook_systemexit_not_0(call_mock):
python_exec = sys.executable
cmd_parts = [python_exec, "-c", "'exit(1)'"] # Forced error code 1
cmd = " ".join(cmd_parts)
run_hook(cmd)
call_mock.assert_called_once_with(cmd, shell=True)
# I need to change the following assertion to
# catch real return code "1"
assert "1" == call_mock.return_value(), \
"Forced system exit(1) should return 1. Just for example purpose"
如何改进此测试以捕获任何subprocess.call
返回码的预期实际值?
出于兼容性目的,无法使用新的subprocess.run
(3.5+)。这个库仍然被python 2.7+环境广泛使用。
答案 0 :(得分:0)
关于subprocess.call,文档说:
运行 args 描述的命令。等待命令完成,然后返回 returncode 属性。
您需要做的就是修改VAR(Zoo, type="both",lag.max = 10,ic="AIC")
函数并返回退出代码:
run_hook
这只是您的测试代码。
def run_hook(cmd):
# ...
return subprocess.call(cmd, shell=True)
我的建议:改为使用def test_run_hook_systemexit_not_0():
python_exec = sys.executable
args = [python_exec, "-c", "'exit(1)'"]
assert run_hook(args) == 1
修改强>
如果您想查看subprocess.run
的退出代码,则需要使用自己的版本进行修补,如下所示:
subprocess.call
然后,您使用import subprocess
_original_call = subprocess.call
def assert_call(*args, **kwargs):
assert _original_call(*args, **kwargs) == 0
作为补丁的副作用函数:
assert_call
答案 1 :(得分:0)
围绕subprocess.call
的包装器可以处理断言验证。
在这种情况下,我将此包装器声明为side_effect
定义中的@patch
参数。
在这种情况下,以下实施方法运作良好。
import sys
import unittest
try:
from unittest.mock import patch
except ImportError:
from mock import patch
def subprocess_call_assert_wrap(expected, message=None):
from subprocess import call as _subcall
def _wrapped(*args, **kwargs):
if message:
assert expected == _subcall(*args, **kwargs), message
else:
assert expected == _subcall(*args, **kwargs)
return _wrapped
class TestCallIsBeingCalled(unittest.TestCase):
@patch("subprocess.call", side_effect=subprocess_call_assert_wrap(expected=0))
def test_run_hook_systemexit_0(self, call_mock):
python_exec = sys.executable
cmd_parts = [python_exec, "-c", "'exit(0)'"]
cmd = " ".join(cmd_parts)
run_hook(cmd)
call_mock.assert_called_once_with(cmd, shell=True)
@patch("subprocess.call", side_effect=subprocess_call_assert_wrap(expected=1))
def test_run_hook_systemexit_not_0(self, call_mock):
python_exec = sys.executable
cmd_parts = [python_exec, "-c", "'exit(1)'"]
cmd = " ".join(cmd_parts)
run_hook(cmd)
call_mock.assert_called_once_with(cmd, shell=True)
采用这种方法进行一些测试后,似乎可以用于更通用的调用,例如:
def assert_wrapper(expected, callable, message=None):
def _wrapped(*args, **kwargs):
if message:
assert expected == callable(*args, **kwargs), message
else:
assert expected == callable(*args, **kwargs)
return _wrapped
这不是最好的方法,但似乎是合理的。
有一些最知名的lib具有类似的行为,我可以在这个项目中使用吗?