如何用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()
原测试代码问题分析
- Mock参数冲突:
@mock.patch同时设置了return_value="123"和side_effect=ValueError,side_effect会覆盖return_value,导致每次调用input()都会直接抛出ValueError,而非返回"123"。 - 异常捕获逻辑不匹配:原函数内部已经捕获了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
相关产品推荐
相关产品推荐

