unittest Mock类实例连续执行用例报TypeError如何解决
问题原因
你遇到的连续执行用例报错,核心是两个问题:
- 手动调用
patcher.start()/stop()管理patch生命周期没有异常兜底,一旦测试逻辑中途抛错,stop()不会执行,patch会直接泄漏到后续用例。加上你直接patch类底层的__new__魔术方法,mock框架对这类特殊方法的还原存在边界bug,导致第一个用例跑完后,SomeClassToMock的__new__被错误替换成了不接收构造参数的原生object.__new__,第二个用例创建真实实例传参时就触发了类型错误。单独跑单个用例时不存在跨用例污染,所以不会报错。 - 你之前尝试直接patch类不生效,99%的原因是patch路径写错了:如果被测模块
module_to_test是用from some.path import SomeClassToMock的方式导入类,那这个模块下会持有类的本地引用,你必须patch这个本地引用,而不是类定义原路径下的对象,否则mock不会生效,这也是你被逼得去改__new__的根本原因。
可行解决方案
不要去patch__new__这种底层魔术方法,直接用mock框架的标准类patch方式,用上下文管理器自动管理patch生命周期,彻底避免泄漏问题,修正后的代码如下:
import unittest from unittest import mock from some.path import SomeClassToMock from path.to.module_to_test import ClassToTest class SomeClassTest(unittest.TestCase): def test_some_method_a(self): # patch启动前先创建真实的预期实例,此时调用的是原生类构造逻辑 mocked_op = SomeClassToMock(**{ "some_key_a": 770675, "some_key_b": "BLAHBLAHBLAHBLAH", "some_key_c": 2740, "some_key_d": 343.4, "some_key_e": "09/06/2022", "some_key_f": "1170720100038737" }) # 注意patch路径是被测模块中持有的SomeClassToMock引用,不是类定义的原路径 # 上下文管理器会自动完成patch启动和还原,哪怕用例报错也不会泄漏 with mock.patch( "path.to.module_to_test.SomeClassToMock", return_value=mocked_op ): effective_op = ClassToTest().method_to_test( "value_a", "value_b", "value_c", "value_d" ) self.assertEqual(mocked_op, effective_op) def test_some_method_b(self): mocked_op = SomeClassToMock(**{ "some_key_a": 770675, "some_key_b": "BLAHBLAHBLAHBLAH", "some_key_c": 2740, "some_key_d": 343.4, "some_key_e": "09/06/2022", "some_key_f": "" }) with mock.patch( "path.to.module_to_test.SomeClassToMock", return_value=mocked_op ): effective_op = ClassToTest().method_to_test( "value_a", "value_b", "value_c", "value_d" ) self.assertEqual(mocked_op, effective_op)
如果你的被测代码里是通过import some.path然后用some.path.SomeClassToMock()的方式调用类,那把patch路径改回"some.path.SomeClassToMock"即可生效,不需要碰__new__。
内容的提问来源于stack exchange,提问作者Eduardo Lúcio
相关产品推荐
相关产品推荐

