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

Pytest中使用monkeypatch传入模拟输入测试函数遇OSError求解

解决pytest模拟输入时的OSError问题

问题场景

尝试用pytest模拟输入测试应用函数,运行测试时触发以下错误:

E OSError: pytest: reading from stdin while output is captured! Consider using -s.

原始应用代码

class Colors:
    def my_colors(self): return colors_split
    # other stuff

class Hobbies:
    def my_hobies(self): return hobbies_split
    # other stuff

colors = input("Colors:")
colors_split = colors.split(",").replace(" ", "")  # 语法错误:列表无replace方法
hobbies = input("Hobbies:")
hobbies_split = hobbies.split(",").replace(" ", "")  # 同上语法错误

原始测试代码

@pytest.fixture(scope="function")
def setup(monkeypatch):
    inputs = iter(["red", "blue", "green"])
    monkeypatch.setattr('builtins.input', lambda _: next(inputs))

def test_my_colors():
    colors = Colors().my_colors()
    assert type(colors) == list

问题原因

  1. 模块顶层提前执行input:应用代码里的input()写在模块最外层,测试代码导入模块时就会立即执行这些input,而此时pytest的monkeypatch fixture还未生效,导致pytest捕获输出时尝试读取真实标准输入,引发OSError。
  2. 语法错误:split()返回列表类型,列表没有replace()方法,会导致应用运行时抛出AttributeError。

修复步骤

1. 重构应用代码,延迟输入执行

将顶层的输入逻辑封装到初始化函数中,避免模块加载时自动执行:

colors_split = []
hobbies_split = []

class Colors:
    def my_colors(self): 
        return colors_split
    # other stuff

class Hobbies:
    def my_hobies(self): 
        return hobbies_split
    # other stuff

def init_app_inputs():
    """初始化应用输入,需在模拟输入后调用"""
    global colors_split, hobbies_split
    colors = input("Colors:")
    # 修正空格处理:用列表推导式去除每个元素的前后空格
    colors_split = [color.strip() for color in colors.split(",")]
    hobbies = input("Hobbies:")
    hobbies_split = [hobby.strip() for hobby in hobbies.split(",")]

2. 修改测试代码,确保monkeypatch生效后初始化输入

在测试中借助fixture,先完成input的模拟替换,再调用应用的初始化函数:

import pytest
from your_app_module import Colors, init_app_inputs  # 替换为实际模块名

@pytest.fixture(scope="function")
def mock_input(monkeypatch):
    # 模拟输入顺序要和应用中input的调用顺序一致:先Colors,再Hobbies
    inputs = iter(["red, green, blue", "reading, hiking"])
    monkeypatch.setattr('builtins.input', lambda _: next(inputs))
    # 调用初始化函数,此时input已被模拟
    init_app_inputs()

def test_my_colors(mock_input):
    colors = Colors().my_colors()
    assert isinstance(colors, list)
    assert colors == ["red", "green", "blue"]

关键说明

  • 把输入逻辑封装到函数中,确保只有测试主动调用时才执行,此时monkeypatch已经替换了builtins.input,不会触发真实的标准输入读取。
  • 用strip()处理每个元素的空格,修正了列表调用replace()的语法错误。
  • 模拟输入的顺序必须和应用中input()的调用顺序严格对应。

内容的提问来源于stack exchange,提问作者user18140022

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 05:03:27