You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:40:21