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

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

问题排查

  1. Patch目标错误:代码中直接使用的open是Python内置函数,而非mockPatch模块自定义的方法。直接patchmockPatch.open无法拦截到实际调用的内置open,导致异常模拟失效。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 20:25:19