Python unittest Mock Patch异常场景测试问题及代码排查
问题排查与解决方案
问题场景
要实现创建空白文件的功能:调用open方法时如果抛出FileExistsError,就先删除文件再重新调用open。测试时通过patch模拟open抛出异常,但测试未正确触发异常逻辑,同时第二次调用open仍会被patch拦截,无法完成正常创建。
用户提供的测试代码如下:
from unittest import TestCase from unittest.mock import patch from os import remove class WriteModule(object): def openBlankFile(self): try: with open("Foo.txt", "x"): print("created") except FileExistsError: remove("Foo.txt") open("Foo.txt", "x") print("removed and created") class testWriteModule(TestCase): @patch("mockPatch.open", side_effect=FileExistsError) @patch("mockPatch.remove") def testWriteModuleOpen(self, mock_remove, mock_open): WriteModule().openBlankFile() if __name__ == "__main__": unittest.main()
运行命令:python -m unittest mockPatch
问题排查
- Patch目标错误:代码中直接使用的
open是Python内置函数,而非mockPatch模块自定义的方法。直接patchmockPatch.open无法拦截到实际调用的内置open,导致异常模拟失效。 - Side_effect设置不合理:当前
side_effect=FileExistsError会让每次调用open都抛出异常,第二次调用open时也会触发异常,无法走到正常创建文件的逻辑。
解决方案
1. 修正Patch目标
将patch的目标改为builtins.open,这样才能正确拦截代码中调用的内置open函数。
2. 控制Side_effect的触发逻辑
设置side_effect为一个列表,让第一次调用open抛出FileExistsError,第二次调用返回一个模拟的文件对象(模拟正常打开成功)。
修改后的测试代码
from unittest import TestCase from unittest.mock import patch, mock_open from os import remove class WriteModule(object): def openBlankFile(self): try: with open("Foo.txt", "x"): print("created") except FileExistsError: remove("Foo.txt") open("Foo.txt", "x") print("removed and created") class testWriteModule(TestCase): @patch("builtins.open", side_effect=[FileExistsError, mock_open()]) @patch("mockPatch.remove") def testWriteModuleOpen(self, mock_remove, mock_open): WriteModule().openBlankFile() # 验证remove被调用了一次 mock_remove.assert_called_once_with("Foo.txt") # 验证open被调用了两次 self.assertEqual(mock_open.call_count, 2) if __name__ == "__main__": import unittest unittest.main()
验证效果
运行修改后的测试代码,会触发except分支的逻辑,同时验证remove和open的调用次数符合预期,测试可以正常通过。
内容的提问来源于stack exchange,提问作者hewi
相关产品推荐
相关产品推荐

