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

如何用pytest捕获name函数输入非法值时抛出的ValueError?

问题排查:非法输入测试用例无法捕获ValueError并陷入循环

正在测试一个要求用户输入纯字母姓名的name()函数:输入非纯字母内容(如"123")时,函数会抛出ValueError并循环重试。合法输入的测试用例test_name运行正常,但非法输入的测试用例test_name_incorrect无法捕获预期的ValueError,甚至需要手动终止测试。

待测试函数代码

def name():
    # Remember user's name
    while True:
        try:
            un = str(input("What's your name? "))
            if not un.isalpha():
                raise ValueError("Please enter a valid name.")
        except ValueError:
            continue
        break
    return un.capitalize()

原测试代码问题分析

  1. Mock参数冲突:@mock.patch同时设置了return_value="123"和side_effect=ValueError,side_effect会覆盖return_value,导致每次调用input()都会直接抛出ValueError,而非返回"123"。
  2. 异常捕获逻辑不匹配:原函数内部已经捕获了ValueError并通过continue继续循环,不会将异常抛出到函数外部。测试用例中用pytest.raises期望捕获函数向外抛出的异常,这完全不符合函数的实际行为,反而会因为函数无限循环导致测试卡住。

修复后的测试方案

场景1:测试非法输入后重试,最终输入合法值的逻辑

这个测试验证函数在遇到非法输入时会继续请求输入,直到获得合法值:

@mock.patch("project.input", side_effect=["123", "sol"])
def test_name_incorrect_then_correct(self):
    actual_result = name()
    expected_result = "Sol"
    assert expected_result == actual_result

场景2:验证非法输入时函数内部的异常触发逻辑

如果需要确认函数在非法输入时正确抛出了目标异常,可以通过mock跟踪异常触发行为,但更实用的是测试函数的重试机制(如场景1所示)。若要直接验证异常抛出,可调整函数逻辑或借助更细粒度的mock,但通常测试函数的实际行为(重试后返回合法结果)更有意义。

修复说明

  • 移除了冲突的side_effect=ValueError,改用side_effect传入输入序列,模拟用户先输入非法值、再输入合法值的过程。
  • 测试不再期望捕获外部异常,而是验证函数最终能返回合法输入的处理结果,完全匹配函数的实际运行逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 13:15:31