如何用pytest为含多轮循环(如带退出条件的while True)的函数Mock输入?
解决多次input调用的monkeypatch模拟问题
你的问题出在两个核心点:
- 多次调用
monkeypatch.setattr("builtins.input")会直接覆盖前一次的设置,所以最后只有返回"Exit"的lambda生效,根本不会用到input_user的值。 - 你在调用
main()之后才设置sys.stdout的mock,这时候main()的输出已经打印到真实控制台了,fake_output根本捕获不到内容。
正确的实现方式
要模拟连续多次的input()调用,你可以用迭代器来提供按顺序的输入值,让每次input()调用依次取出迭代器里的元素。同时要先设置好stdout的mock,再执行main()。
修改后的测试代码如下:
from io import StringIO def test_main_scenario(input_user, expected, monkeypatch): # 用迭代器提供连续输入:先返回input_user,再返回"Exit" inputs = iter([input_user, "Exit"]) monkeypatch.setattr("builtins.input", lambda _: next(inputs)) # 先捕获stdout,再执行main fake_output = StringIO() monkeypatch.setattr("sys.stdout", fake_output) main() # 获取捕获的输出并断言 output = fake_output.getvalue() assert output == expected
代码解释
- 迭代器模拟连续输入:
iter([input_user, "Exit"])创建一个迭代器,每次调用next(inputs)会依次取出列表里的元素。把这个逻辑传给builtins.input,就能让main()里第一次input()拿到input_user,第二次拿到"Exit",从而触发循环退出。 - 提前设置stdout mock:在调用
main()之前就把sys.stdout替换成StringIO实例,这样main()里所有的print内容都会被写入到fake_output里,后续就能正确获取并断言。
如果需要模拟更多次输入,只需要在迭代器的列表里添加对应的值即可,比如iter(["first", "second", "Exit"])就能模拟三次输入。
内容的提问来源于stack exchange,提问作者Iraedeus
相关产品推荐
相关产品推荐

