Python如何正确Mock非法YAML文件并断言异常?
如何在Python中Mock无效YAML文件并测试异常场景
咱们来拆解下你的两种测试思路,把其中的小问题修正后,就能正确触发无效YAML的异常并验证预期行为了。
先理清楚你的代码逻辑
首先,你的MyClass里,get_parameters方法会捕获加载YAML时的所有异常,返回None同时记录错误日志。所以你的测试目标应该是两个:一是确认get_params()最终返回None,二是验证错误日志被正确输出。
方法1:Mock os.path.isfile 和 open 的修正方案
你的第一种思路方向是对的,但有几个细节需要调整:
- Mock路径要准确:
patch的目标必须是对象被实际调用的位置。比如如果MyClass在my_module.py里,那你应该Mockmy_module.open,而不是__main__.open(除非测试代码和MyClass在同一个主模块)。 - 需要验证日志输出:既然代码里用
Log.error记录了错误,测试里最好也验证这个日志是否被正确调用。
修正后的完整测试代码:
from unittest.mock import patch, mock_open import unittest from your_module import MyClass # 替换成你的MyClass所在模块名 class TestMyClass(unittest.TestCase): def test_illegal_yaml_file(self): # Mock Log.error,用来验证错误日志是否被触发 with patch('your_module.Log.error') as mock_log_error: # Mock os.path.isfile,让它认为配置文件存在 with patch('os.path.isfile', return_value=True): # Mock open函数,返回非法格式的YAML内容 invalid_yaml_content = 'wifi_password 12345678' # 缺少冒号,属于无效YAML with patch('your_module.open', mock_open(read_data=invalid_yaml_content)): my_obj = MyClass() params = my_obj.get_params() # 断言最终返回None self.assertIsNone(params) # 断言错误日志被调用,且包含预期提示 mock_log_error.assert_called_once() self.assertIn('Invalid YAML file', mock_log_error.call_args[0][0])
方法2:直接传入IO对象的修正方案
这种思路是单独测试yaml_load静态方法,更偏向单元测试,但有个小问题:你用了io.BytesIO,而yaml.load处理文本内容时,用io.StringIO更合适(避免编码问题)。另外要根据yaml_load的参数类型调整传入内容:
如果yaml_load接受文件对象
import io import yaml import unittest from your_module import MyClass class TestMyClass(unittest.TestCase): def test_illegal_yaml_via_io(self): # 用StringIO传递非法YAML文本 invalid_yaml_io = io.StringIO('param 12345678') # 因为yaml_load没有捕获异常,所以直接断言抛出YAMLError with self.assertRaises(yaml.YAMLError): MyClass.yaml_load(invalid_yaml_io)
如果yaml_load接受字符串
import yaml import unittest from your_module import MyClass class TestMyClass(unittest.TestCase): def test_illegal_yaml_via_string(self): invalid_yaml_str = 'param 12345678' with self.assertRaises(yaml.YAMLError): MyClass.yaml_load(invalid_yaml_str)
不过要注意:这种方法只能测试yaml_load本身的异常行为,如果要测试从get_params到加载文件的完整流程,还是方法1更合适。
几个关键注意点
- Mock路径原则:记住
patch要Mock对象被使用的路径,而不是定义的路径。比如MyClass里调用的open,属于MyClass所在模块的open,所以要Mock那个模块下的open。 - 捕获具体异常:建议把
get_parameters里的Exception换成具体的yaml.YAMLError,这样测试更精准,也不会意外捕获其他无关异常。 - 日志验证:验证日志调用能确保代码确实识别到了无效YAML并做了正确的错误记录。
内容的提问来源于stack exchange,提问作者Zusman
相关产品推荐
相关产品推荐

