如何在单元测试中Mock导入类实例方法内的open操作?
问题:Mock文件写入时mock_calls为空的排查方案
我需要测试自定义Builder类的build方法,该方法会将内容写入文件。为避免测试时实际创建文件,希望通过mock_open模拟写入过程,分析mock对象的call_args获取拟写入的内容。但编写model.py和test_model.py后,尝试多种patch目标,mock_calls始终为空,return_value.write.call_args返回None,请求排查问题。
原代码展示
model.py
class Builder: def __init__(self, input_template_map, output_filename, output_dir=""): self.input_template_map = input_template_map self.output_filename = output_filename self.output_dir = output_dir def build(self): output = "" # 一些读取文件生成output的代码 with open(f"{self.output_dir}/{self.output_filename}.EB", "w") as f: f.write(output)
test_model.py
import unittest from unittest.mock import mock_open, MagicMock, patch from model import Builder class ModelTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.builder = Builder({}, output_filename="test_out", output_dir="outputs") def test_build(self): m = mock_open() with patch("model.Builder.build.open", m, create=True): self.builder.build() print(m.mock_calls) print(m.return_value.write.call_args)
问题原因及解决方案
错误原因
你patch的目标路径错误。build方法中调用的open是全局内置函数,并非Builder.build方法的属性,所以patch("model.Builder.build.open")不会拦截到实际的open调用,导致mock对象没有任何调用记录。
正确解决方案
需要patchBuilder类所在模块(model)中的open引用,或者直接patch全局的builtins.open,推荐前者,避免影响其他测试用例。
修改后的test_build方法如下:
def test_build(self): m = mock_open() # 正确patch model模块中的open with patch("model.open", m): self.builder.build() # 打印所有mock调用记录 print(m.mock_calls) # 获取write方法的调用参数 print(m.return_value.write.call_args) # 可以添加断言验证写入内容 m.return_value.write.assert_called_once_with("")
原理说明
Python的mock是基于在哪里被调用而不是在哪里定义来生效的。Builder.build方法在model模块中调用了open,所以需要patchmodel模块下的open引用,这样当build方法调用open时,会使用你提供的mock对象,从而记录下所有调用行为。
内容的提问来源于stack exchange,提问作者cadeaudecheval
相关产品推荐
相关产品推荐

