为何触发ValueError后Python单元测试仍未检测到该异常?
问题描述
我在完成Python课程作业时编写了get_funcs函数,当传入file_name为"test.csv"或"test"时会抛出ValueError,该异常会被函数内的try-except块捕获并通过print_log记录。但使用unittest的assertRaises进行测试时,明明能看到异常被抛出并记录,测试却失败,无法检测到这个ValueError。尝试将异常抛出移到try块外、新增ValueError捕获分支都无效,想知道原因。
函数代码
def get_funcs(funcs: dict, file_name: str, table_name: str) -> None: ''' Read the given *.csv file, store the data inside the database and store the functions in a dict Args: functions dict: Dictionary to store the functions object file_name str: The file name of the csv-file with file extension table_name str: The name of the SQL table ''' global update_database try: if file_name == "test.csv" or file_name == "test": raise ValueError("The function for the test data is not neccessary.") elif file_name != "train.csv" and file_name != "train" and file_name != "ideal.csv" and file_name != "ideal": raise ValueError("Given a completly wrong / empty file or a directorys.") # store the complete path to the file in a variable complete_path = os.path.join(dataset_dir, file_name) # check file to be correct file_extension = os.path.splitext(file_name)[1] if file_extension == "": print_log(MessageType.Warn, "get_funcs", "Missing file extension. Added ".csv" automatically!") complete_path += ".csv" if not os.path.exists(complete_path): raise FileNotFoundError() # read csv file and store it in a data frame data = pd.read_csv(complete_path, sep=",") print_log(MessageType.Info, "get_funcs", "Successfully read \"" + file_name + "\"!") except PermissionError as error: print_log(MessageType.Error, "get_funcs", "Cannot open the given csv file!") return except Exception as error: print_log(MessageType.Error, "get_funcs", error) return
测试代码
import main import unittest class UnitTestPythonTask(unittest.TestCase): def test_check_test_function(self): ''' Checks the file validation of the given .csv files ''' self.assertRaises(ValueError, main.get_funcs({}, "test.csv", "TestFunction"))
原因分析
核心问题在于函数内部已经捕获了抛出的ValueError,没有将异常传递到函数外部。assertRaises的作用是检测函数执行时向外抛出的异常,但你的get_funcs函数中,抛出的ValueError被最下方的except Exception块捕获,随后执行了print_log和return,异常根本没有传到函数外部,因此unittest无法检测到它。
哪怕你把异常抛出移到try块外,只要后续还是被try-except包裹(或者函数内其他except块捕获),异常依然不会向外传递;新增ValueError捕获分支但没有重新抛出的话,同样会拦截异常,导致unittest检测失败。
解决方案
方案1:让异常向外传递
修改函数的异常处理逻辑,在捕获ValueError后重新抛出,这样unittest就能检测到:
except PermissionError as error: print_log(MessageType.Error, "get_funcs", "Cannot open the given csv file!") return except ValueError as error: print_log(MessageType.Error, "get_funcs", error) raise # 重新抛出异常,让unittest捕获 except Exception as error: print_log(MessageType.Error, "get_funcs", error) return
方案2:不拦截特定的ValueError
如果不需要在函数内处理这类ValueError,可以直接移除对它的捕获,让它自然向外抛出:
try: # 原有逻辑... except PermissionError as error: print_log(MessageType.Error, "get_funcs", "Cannot open the given csv file!") return # 移除对Exception的捕获,或者调整捕获范围,排除测试用的ValueError
方案3:测试日志输出(不修改函数逻辑)
如果不想修改函数的异常处理逻辑,可以转而测试print_log是否输出了对应的错误信息。可以通过模拟print_log函数来验证:
from unittest.mock import patch def test_check_test_function(self): with patch('main.print_log') as mock_print_log: main.get_funcs({}, "test.csv", "TestFunction") mock_print_log.assert_called_with( main.MessageType.Error, "get_funcs", "The function for the test data is not neccessary." )
内容的提问来源于stack exchange,提问作者grafj73

