使用pytest-mock模拟subprocess.Popen编写Python单元测试
用pytest和pytest-mock测试调用subprocess的函数
没问题,我来帮你搞定这个单元测试的事儿!咱们的核心思路是mock掉subprocess.Popen,避免真的执行系统命令,同时模拟它的返回结果,来验证你的函数f()是否正确处理了各种情况。
下面分几种场景给出具体的测试代码:
1. 测试命令正常执行的情况
这个场景下,我们模拟命令成功执行(退出码为0),且没有错误输出,同时验证函数是否正确调用了目标命令。
import pytest from your_module import f, command # 替换成你的实际模块名 def test_f_command_success(mocker): # 1. Mock subprocess.Popen对象 mock_popen = mocker.patch('subprocess.Popen') mock_proc = mock_popen.return_value # 2. 模拟命令执行成功的返回值 mock_proc.wait.return_value = 0 mock_proc.stderr.read.return_value = b'' # 空的错误输出 # 3. 调用要测试的函数 f() # 4. 验证调用逻辑是否符合预期 mock_popen.assert_called_once_with(command, ...some_args...) # 替换成函数里实际的some_args参数 mock_proc.wait.assert_called_once() mock_proc.stderr.read.assert_called_once() # 如果函数里有处理文件内容的逻辑,可以额外mock文件操作来验证 # 示例:mock文件读取,验证是否读取了目标文件 # mock_open = mocker.patch('builtins.open', mocker.mock_open(read_data='expected_content')) # mock_open.assert_called_once_with('your_target_file_path', 'r')
2. 测试命令执行失败的情况
这个场景模拟命令执行出错(退出码非0),且有错误输出,验证函数是否正确处理了错误信息和错误码。
def test_f_command_failure(mocker): mock_popen = mocker.patch('subprocess.Popen') mock_proc = mock_popen.return_value # 模拟失败场景:退出码1,错误输出为权限不足提示 mock_proc.wait.return_value = 1 mock_proc.stderr.read.return_value = b"Permission denied" f() # 验证调用逻辑 mock_popen.assert_called_once_with(command, ...some_args...) mock_proc.wait.assert_called_once() mock_proc.stderr.read.assert_called_once() # 如果函数有针对错误的处理逻辑(比如抛出异常、记录日志),这里可以添加对应断言 # 示例:如果函数会抛出自定义异常 # with pytest.raises(CommandExecutionError) as excinfo: # f() # assert excinfo.value.args[0] == "Permission denied"
3. 测试自定义命令的情况(可选)
如果想要测试不同命令传入的情况,可以直接替换模块中的全局command变量:
def test_f_with_custom_command(mocker): custom_command = 'echo "test content" > temp.txt' # 替换模块中的全局command变量 mocker.patch('your_module.command', custom_command) mock_popen = mocker.patch('subprocess.Popen') mock_proc = mock_popen.return_value mock_proc.wait.return_value = 0 mock_proc.stderr.read.return_value = b'' f() # 验证Popen使用了自定义的命令 mock_popen.assert_called_once_with(custom_command, ...some_args...)
关键要点说明
- mock路径要准确:如果你的模块里是直接
import subprocess后使用subprocess.Popen,那么mock'subprocess.Popen'就可以;如果是从其他地方导入的,要对应调整mock路径。 - 模拟返回值:通过
mock_proc.wait.return_value和mock_proc.stderr.read.return_value可以灵活模拟各种执行结果。 - 断言调用细节:用
assert_called_once_with能确保命令和参数被正确传递,避免函数逻辑出现偏差。
内容的提问来源于stack exchange,提问作者sinecode
相关产品推荐
相关产品推荐

