我想测试一个函数,它调用subprocess.Popen并捕获stdout.特别是,我需要测试stdout个物理捕获在磁盘上的文件中的内容,而无需调用实际的进程.

示例函数:

import subprocess

def func():
    with open('stdout.txt', 'wt') as out:
        subprocess.Popen(_cmdline(), stdout=out)

def _cmdline() -> list[str]:
    # Or whatever process we want to run
    return ['ls']

测试功能:

from unittest import mock

def test_captures_stdout():
    with mock.patch('subprocess.Popen') as mock_popen:
        func()

    # Try to intercept stdout and write to it
    [(_, kwargs)] = mock_popen.call_args_list
    with kwargs['stdout']:
        buf.write('some standard output')

    with open('stdout.txt') as buf:
        assert buf.read() == 'some standard output'

在这里,我模拟subprocess.Popen,然后拦截传递给它的构造函数的stdout,并try 写入缓冲区.然后,我打算对stdout.txt文件的内容运行断言.

显然,当我try 写入stdout缓冲区时,它已经关闭,并且我收到IO错误.

================================== FAILURES ===================================
____________________________ test_captures_stdout _____________________________

    def test_captures_stdout():
        with mock.patch('subprocess.Popen') as mock_popen:
            func()

        # Try to intercept stdout and write to it
        [(_, kwargs)] = mock_popen.call_args_list
>       with kwargs['stdout']:
E       ValueError: I/O operation on closed file.

test_subprocess.py:22: ValueError
=========================== short test summary info ===========================

我想知道是否有一种方便的方法来模拟Popen并以某种方式模拟写入到文件中的stdout.

推荐答案

您的单元测试实际上是没有意义的,因为它在返回func之后将测试内容直接写入文件对象,因此不仅文件对象已经关闭,因此无效,而且调用Popen之后依赖输出内容的任何逻辑都不会工作,因为在调用func期间没有内容写入文件对象.

相反,您可以使用side effect的函数来修补Popen,该函数通过将测试内容写入给定的stdout文件对象来模拟Popen构造函数:

def test_captures_stdout():
    def mock_popen(cmd, stdout, **kwargs):
        stdout.write('some standard output')

    with mock.patch('subprocess.Popen', autospec=True, side_effect=mock_popen):
        func()

    with open('stdout.txt') as buf:
        assert buf.read() == 'some standard output'

演示:https://replit.com/@blhsing1/FuchsiaMerryScandisk

Python相关问答推荐

如何在Deliveryter笔记本中从同步上下文正确地安排和等待Delivercio代码中的结果?

Select 用a和i标签包裹的复选框?

Pandas 在最近的日期合并,考虑到破产

为什么默认情况下所有Python类都是可调用的?

使用密钥字典重新配置嵌套字典密钥名

如何在turtle中不使用write()来绘制填充字母(例如OEG)

为什么numpy. vectorize调用vectorized函数的次数比vector中的元素要多?

python—telegraph—bot send_voice发送空文件

如何创建引用列表并分配值的Systemrame列

使用Openpyxl从Excel中的折线图更改图表样式

PYTHON、VLC、RTSP.屏幕截图不起作用

如何从pandas DataFrame中获取. groupby()和. agg()之后的子列?

Python pint将1/华氏度转换为1/摄氏度°°

Pandas在rame中在组内洗牌行,保持相对组的顺序不变,

Python如何导入类的实例

如何防止html代码出现在quarto gfm报告中的pandas表之上

极柱内丢失类型信息""

我如何为测试函数的参数化提供fixture 生成的数据?如果我可以的话,还有其他 Select 吗?

Python:在cmd中添加参数时的语法

使用元组扩展字典的产品挑战