我有一个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不变,并在调用SUT中的os.system
之前在测试方法中全局替换main()
。
这给我带来了新的问题,因为这是一个全球性和持久的变化。很好,所以我在同一个测试方法中使用try/finally
,并在离开测试方法之前替换原始版本。无论测试方法是通过还是失败,它都能正常工作。
是否有一种安全且优雅以设置/拆解为中心的方式为PyTest执行此操作?
其他并发症:我想对stdout和stderr做同样的事情。是的,它确实是我正在测试的main()
脚本。
答案 0 :(得分:3)
Python 3(> = 3.3)标准库在官方文档中有great tutorial about Mock。对于Python 2,您可以在PyPi上使用反向移植的库:Mock。
以下是一个示例用法。假设您要在此函数中模拟对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
最后会恢复。
然后,有几个"断言"检查调用,参数和结果的方法。您还可以检查在某些情况下是否会引发异常。
答案 1 :(得分:1)
只想添加一个重要的细节。
如果您的代码使用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()
这让我有些困惑,因为我忘记了按原本打算阅读where to patch上的这一节。如果修补程序似乎不起作用,那么这是需要研究的重点之一。