我想测试一个函数,它调用
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
写入文件。
您的单元测试毫无意义,因为它在
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'