测试用户输入函数抛出ValueError的单元测试失败,求解决方案
问题描述
我在完成作业时需要测试接受用户输入的函数是否会根据输入抛出ValueError异常。以下是待测试的Python代码:
def prompt_num_integers(): while True: try: # converting to int raises ValueError if input can't convert num_of_integers = int(input("How many integers do you want to store: ")) if num_of_integers < 1: raise ValueError except ValueError: print("Sorry, I didn't quite understand that.") continue else: return num_of_integers def prompt_integers(): # prompt user for number of integers then store that value into a variable num_of_integers = prompt_num_integers() # list for storing the integers integer_list = [] # integer for keeping count of current num of integers x = 0 while x < num_of_integers: try: # check if current num of integer equals total num of integers wanted, then give appropriate prompt if x == num_of_integers - 1: integer = int(input("Input last integer: ")) else: integer = int(input("Input integer: ")) except ValueError: print("Sorry, I didn't quite understand that.") continue else: # add correct integer to integer list, then update current num of integers variable integer_list.append(integer) x += 1 print(f"List of integers: {integer_list}") return integer_list
我用unittest和mock编写的单元测试代码如下:
import unittest import unittest.mock as mock import GatheringInputFunctionsKing as Test class MyTestCase(unittest.TestCase): def test_a_function_throws_exception(self): with mock.patch('builtins.input', side_effect=[0,1,1]): self.assertRaises(ValueError, Test.prompt_integers)
测试执行后失败,报错信息:
Ran 1 test in 0.004s FAILED (failures=1) Failure Traceback (most recent call last): File "C:\Users\Sam\PycharmProjects\CIS289_Module1\Test_GatheringInputFunctions.py", line 10, in test_a_function_throws_exception self.assertRaises(ValueError, Test.prompt_integers) AssertionError: ValueError not raised by prompt_integers
即使单独测试prompt_num_integers函数,也会得到相同的失败结果,请问该如何解决?
问题原因
测试失败的核心原因是:目标函数内部已经捕获了ValueError,并没有将异常抛出到函数外部。
看prompt_num_integers和prompt_integers的代码逻辑:
- 在
prompt_num_integers中,无论是输入无法转成整数的字符串,还是输入小于1的数字,触发的ValueError都会被内部的except ValueError块捕获,随后执行continue进入下一次循环,不会把异常抛到函数外部。 prompt_integers调用prompt_num_integers时,同样不会收到任何抛出的异常,所以assertRaises无法检测到ValueError。
解决方案
当前函数的设计是内部处理异常,循环直到获得有效输入,因此测试的重点应该是验证:当输入无效值时,函数会重新提示输入,并最终返回正确的有效结果。
调整后的单元测试代码
import unittest import unittest.mock as mock import GatheringInputFunctionsKing as Test class MyTestCase(unittest.TestCase): def test_prompt_num_integers_handles_invalid_input(self): # 模拟输入:先输入0(无效)、再输入"abc"(无效)、最后输入3(有效) with mock.patch('builtins.input', side_effect=[0, "abc", 3]), mock.patch('builtins.print') as mock_print: result = Test.prompt_num_integers() # 验证最终返回的有效数字正确 self.assertEqual(result, 3) # 验证无效输入时打印了两次提示信息 mock_print.assert_has_calls([ mock.call("Sorry, I didn't quite understand that."), mock.call("Sorry, I didn't quite understand that.") ]) def test_prompt_integers_handles_invalid_input(self): # 模拟输入:先输入2(需要2个整数)、然后输入"xyz"(无效)、再输入10、最后输入20 with mock.patch('builtins.input', side_effect=[2, "xyz", 10, 20]), mock.patch('builtins.print') as mock_print: result = Test.prompt_integers() # 验证最终返回的整数列表正确 self.assertEqual(result, [10, 20]) # 验证无效输入时打印了一次提示信息 mock_print.assert_any_call("Sorry, I didn't quite understand that.") if __name__ == '__main__': unittest.main()
关键说明
- 模拟
print函数:用mock.patch('builtins.print')捕获打印的提示信息,验证无效输入时确实触发了错误提示。 - 模拟输入序列:通过
side_effect按顺序模拟用户的输入,包含无效值和最终的有效值,验证函数会循环直到获得有效输入。 - 验证返回结果:确认函数最终返回的是正确的有效输入结果。
如果确实需要让函数在某些场景下向外抛出异常,你需要修改原函数的逻辑,比如去掉内部的try-except块,或者在特定条件下重新抛出异常,但这不符合当前函数“容错式输入提示”的设计意图。
内容的提问来源于stack exchange,提问作者Byotic
相关产品推荐
相关产品推荐

