我有一个python脚本,可以进行多个os.system
调用。宣称针对它们的系列列表很容易(而且相对优雅)。
什么并不容易的是拦截(并阻止)实际调用。在有问题的脚本中,我可以在SUT中抽象OS.System(*)这样的系统:
os_system = None
def main():
return do_the_thing(os.system)
def do_the_thing(os_sys):
global os_system
os_system = os_sys
# all other function should use os_system instead of os.system
我的测试当然会调用my_script.do_the_thing()
而不是my_script.main()
(留下少量未经测试的代码)。
替代选项:我可以在调用sut中调用 main()
之前,在测试方法中全球替换 os.system
。
这给我留下了新的问题,因为这是一个全球性和持久的变化。好的,所以我会在相同的测试方法中使用try/finally
,然后在离开测试方法之前替换原件。测试方法通过还是失败。
是否有安全且优雅设置/以拆卸为中心的方式为pytest做到这一点?
其他并发症:我想为Stdout和Stderr做同样的事情。是的,这确实是我正在测试的main()
脚本。
- SUT ==系统正在测试
python 3(> = 3.3)标准库在官方文档中具有关于模拟的出色教程。对于Python 2,您可以使用Backported Library:PYPI上的模拟。
这是示例用法。说您想在此功能中模拟对os.system
的调用:
import os
def my_function(src_dir):
os.system('ls ' + src_dir)
为此,您可以使用unittest.mock.patch
装饰器,例如:
import unittest.mock
@unittest.mock.patch('os.system')
def test_my_function(os_system):
# type: (unittest.mock.Mock) -> None
my_function("/path/to/dir")
os_system.assert_called_once_with('ls /path/to/dir')
此测试功能将在执行过程中修补os.system
调用。os.system
在末尾还原。
然后,有几种"断言"方法可以检查呼叫,参数和结果。您还可以检查某些CirconStances是否提出了例外。
只想添加一个重要的细节。
如果您的代码使用import system
,例如:
myls.py :
import os
def do_ls():
os.system('ls')
然后您的测试中的补丁应该看起来像:
test_myls.py :
from unittest.mock import patch
@patch('os.system')
def test_do_ls(mock_system):
do_ls()
mock_system.assert_called()
但是,如果代码使用from os import system
,例如这样:
myls.py :
from os import system
def do_ls():
system('ls')
然后您的测试中的补丁应该看起来像:
test_myls.py :
from unittest.mock import patch
@patch('myls.system')
def test_do_ls(mock_system):
do_ls()
mock_system.assert_called()
这让我有些不安,因为我忘了阅读有关我最初预期的何处修补的部分。如果修补似乎不起作用,这是要查看的要点之一。