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

测试用户输入函数抛出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()

关键说明

  1. 模拟print函数:用mock.patch('builtins.print')捕获打印的提示信息,验证无效输入时确实触发了错误提示。
  2. 模拟输入序列:通过side_effect按顺序模拟用户的输入,包含无效值和最终的有效值,验证函数会循环直到获得有效输入。
  3. 验证返回结果:确认函数最终返回的是正确的有效输入结果。

如果确实需要让函数在某些场景下向外抛出异常,你需要修改原函数的逻辑,比如去掉内部的try-except块,或者在特定条件下重新抛出异常,但这不符合当前函数“容错式输入提示”的设计意图。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 02:25:35