Python unittest的setUp函数未应用类级别声明的patch mock问题
问题原因
你遇到的问题是unittest框架的执行顺序和patch装饰器的生效时机不匹配导致的:
类级别挂载的@patch装饰器,实际作用是给测试类下的每一个测试方法单独包裹mock逻辑,mock的生效窗口为测试方法开始执行前到测试方法执行结束后。而setUp方法的调用时机在patch激活之前,所以setUp中运行的代码无法用到类装饰器声明的mock,只会调用真实的业务逻辑。
这也能解释你观察到的现象:把实例化逻辑放到测试方法内、或者在测试方法开头手动调用自定义初始化方法时,patch已经激活,mock就能正常生效。
解决方法
推荐优先使用在setUp中手动管理patch生命周期的方案,既可以保留setUp复用初始化逻辑的能力,也能保证mock在初始化阶段正常生效,代码示例如下:
import unittest from unittest.mock import patch class TestInitBase(unittest.TestCase): def setUp(self): """ Code that executes before every function. """ # 第一步:启动所有mock补丁 self.patches = [ patch('geomet_data_registry.layer.base.get_today_and_now', new=mocked_get_date), patch('geomet_data_registry.layer.base.load_plugin', new=mocked_load_plugin), patch('geomet_data_registry.layer.base.TILEINDEX_PROVIDER_DEF', new=mocked_tileindex), patch('geomet_data_registry.layer.base.STORE_PROVIDER_DEF', new=mocked_store) ] for p in self.patches: p.start() # 第二步:执行原有初始化逻辑,此时mock已全部生效 self.maxDiff = None self.today_date = \ datetime.now(timezone.utc).isoformat().replace('+00:00', 'Z') mocked_get_date.return_value = self.today_date self.base_layer = BaseLayer({'name': 'model_gem_global'}) def tearDown(self): # 测试结束后统一停止所有补丁,避免影响其他测试 for p in self.patches: p.stop() def test_Init(self): expected_values = {'items': [],...} base_layer_attr = self.base_layer.__dict__ self.assertDictEqual(expected_values, base_layer_attr, msg=None)
如果不想调整patch的挂载方式,也可以选择保留类上的@patch装饰器,将需要依赖mock的初始化逻辑封装为普通方法,在每个测试方法开头手动调用,和你之前测试可行的mySetUp方案一致。
内容的提问来源于stack exchange,提问作者PhilippeTh
相关产品推荐
相关产品推荐

