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

如何对含input()和print()循环的函数进行单元测试(含pytest方案)

优化Python函数的输入输出测试方案(unittest + pytest)

待测试的Python函数:

def welcome():
    for i in range(2):  # 实际代码中是range(100)
        name = input("enter your name")
        print("welcome " + name)

一、unittest优化方案

你之前的代码核心问题是装饰器参数顺序搞反了:@mock.patch是从下往上生效的,所以被装饰的测试方法参数顺序应该是最后一个装饰器的mock对象在前。另外可以用assert_has_calls一次性验证所有print调用,简化断言逻辑。

优化后的代码:

import unittest
from unittest import mock
from unittest.mock import call
import welcome

class WelcomeTests(unittest.TestCase):
    @mock.patch('builtins.print')
    @mock.patch('welcome.input')
    def test_welcome_with_multiple_inputs(self, mocked_input, mock_print):
        # 设置模拟输入的序列
        mocked_input.side_effect = ["Alice", "Bob"]
        # 执行待测试函数
        welcome.welcome()
        # 验证print的所有调用(顺序和内容都要匹配)
        mock_print.assert_has_calls([
            call("welcome Alice"),
            call("welcome Bob")
        ], any_order=False)

if __name__ == '__main__':
    unittest.main()

关键说明:

  • 调整@mock.patch顺序,确保测试方法参数和装饰器顺序对应(最后装饰的mock先作为参数传入)
  • 使用unittest.mock.call构建预期的调用对象,配合assert_has_calls验证多次调用的顺序和内容
  • 去掉不必要的调试代码,让测试逻辑更清晰

二、pytest实现方案

用pytest的monkeypatch fixture可以更简洁地模拟输入和捕获输出:

import pytest
import welcome

def test_welcome_with_multiple_inputs(monkeypatch):
    # 模拟input的返回值序列
    inputs = ["Alice", "Bob"]
    monkeypatch.setattr('builtins.input', lambda _: inputs.pop(0))
    
    # 捕获print的输出
    printed_lines = []
    monkeypatch.setattr('builtins.print', lambda x: printed_lines.append(x))
    
    # 执行待测试函数
    welcome.welcome()
    
    # 断言输出内容
    assert printed_lines == ["welcome Alice", "welcome Bob"]

关键说明:

  • 用monkeypatch.setattr替换input,每次调用返回序列中的下一个值
  • 替换print为一个收集输出的函数,把每次打印的内容存入列表
  • 直接断言收集到的输出列表和预期一致,逻辑直观易懂

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 02:00:08