使用Python fileinput模块时如何模拟stdin输入?
解决fileinput模块单元测试中stdin模拟的OSError问题
问题原因
当使用fileinput.input("-")时,模块会尝试读取真实的sys.stdin,而pytest默认捕获stdout/stderr的机制会锁定stdin,从而抛出OSError: reading from stdin while output is captured错误。你之前测试中mockraw_input的做法无效,因为fileinput根本不依赖这个函数。
两种可行解决方案
方案一:直接mock fileinput.input(推荐)
绕开真实stdin读取,直接让fileinput.input返回测试用的行数据:
import io from unittest import mock import my_fileinput def test_stdin(): """测试fileinput读取stdin的场景""" # 模拟fileinput返回的行数据(注意包含换行符,和真实读取一致) with mock.patch("my_fileinput.fileinput.input", return_value=["42\n"]): with mock.patch("sys.stdout", new=io.StringIO()) as stdout: with mock.patch("sys.argv", ["my_fileinput.py", "-"]): my_fileinput.main() assert stdout.getvalue() == "answer #1: 42\n"
方案二:模拟sys.stdin并配合pytest工具
通过monkeypatch模拟sys.stdin,同时用capsys捕获输出:
import io import pytest import my_fileinput def test_stdin(capsys, monkeypatch): """测试fileinput读取stdin的场景""" # 模拟stdin输入内容 monkeypatch.setattr("sys.stdin", io.StringIO("42\n")) # 设置命令行参数为"-",表示读取stdin monkeypatch.setattr("sys.argv", ["my_fileinput.py", "-"]) my_fileinput.main() # 捕获输出结果 captured = capsys.readouterr() assert captured.out == "answer #1: 42\n"
注意事项
- 测试断言要匹配实际输出:原代码中
sys.stdout.write的内容包含fileinput.lineno()和输入的行(带换行符),所以断言字符串要包含\n。 - 避免直接操作真实stdin:在测试环境中,直接读取真实stdin会和pytest的捕获机制冲突,必须通过模拟绕过。
内容的提问来源于stack exchange,提问作者tschutter
相关产品推荐
相关产品推荐

