在假子进程中模拟标准输出。Popen

问题描述 投票:0回答:1

我想测试一个函数,它调用

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
并尝试写入缓冲区。然后我打算对
stdout.txt
文件的内容运行断言。

显然,当我尝试写入

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
写入文件。

python testing mocking subprocess
1个回答
0
投票

您的单元测试毫无意义,因为它在

func
返回后直接将测试内容直接写入文件对象,因此不仅文件对象已经关闭并因此无效,而且调用
 后的任何逻辑都无效依赖于输出内容的Popen
将不起作用,因为在调用
func
期间没有内容写入文件对象。

您可以通过将测试内容写入给定的

Popen
文件对象,使用模拟 Popen 构造函数的函数的
副作用
来修补
stdout

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

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

    with open('stdout.txt') as buf:
        assert buf.read() == 'some standard output'
© www.soinside.com 2019 - 2024. All rights reserved.