模拟单元测试(PYTEST)的模拟OS.System的最佳方法是什么?



我有一个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()

这让我有些不安,因为我忘了阅读有关我最初预期的何处修补的部分。如果修补似乎不起作用,这是要查看的要点之一。

最新更新