为何mock.patch类装饰器无法生效?类级别装饰失效原因咨询
@mock.patch无法生效? 这个问题的核心原因是:mock.patch装饰类的时候,它的作用范围是类内部的测试方法(比如遵循test_*命名规范的unittest测试方法),而不是让类的所有实例方法在任何时候都自动应用这个补丁。
具体分析你的代码
当你用@mock.patch('time.sleep', mock.Mock(side_effect=Exception('dooooom')))装饰Foo类时,这个补丁并不会自动作用于Foo.bar方法的执行过程。因为mock.patch针对类的装饰逻辑是为测试框架设计的——它会给类里每个以test_开头的方法自动注入补丁,并且只在这些测试方法运行期间生效。而你的bar方法不是测试方法,所以实例化Foo并调用bar时,time.sleep还是系统原生的方法,自然不会抛出异常。
而当你把补丁下移到装饰bar方法时,每次调用bar都会触发mock.patch的逻辑:先替换time.sleep为你定义的Mock对象,执行方法代码,然后再恢复原方法。所以此时time.sleep(1)会触发你设置的异常,完全符合预期。
如何让类级别的补丁生效?
如果你希望类的所有方法在调用时都应用这个补丁,有几种可行的方式:
使用上下文管理器包裹方法调用:
f = Foo() with mock.patch('time.sleep', mock.Mock(side_effect=Exception('dooooom'))): f.bar()这种方式灵活可控,补丁只在
with代码块内生效,不会影响其他代码的执行。在类的初始化方法中手动打补丁:
class Foo(object): def __init__(self): self.patcher = mock.patch('time.sleep', mock.Mock(side_effect=Exception('dooooom'))) self.patcher.start() def __del__(self): self.patcher.stop() def bar(self): print('before') time.sleep(1) print('after')这样实例化
Foo后,所有方法调用都会应用补丁,但要注意在类销毁时正确停止补丁,避免内存泄漏。如果是测试场景,把测试方法放在类内:
如果你是在写单元测试,类级别的mock.patch会正常工作,比如:import unittest import time import six if six.PY2: import mock else: from unittest import mock class Foo(object): def bar(self): print('before') time.sleep(1) print('after') class TestFoo(unittest.TestCase): @mock.patch('time.sleep', mock.Mock(side_effect=Exception('dooooom'))) def test_bar(self): f = Foo() with self.assertRaises(Exception) as ctx: f.bar() self.assertEqual(str(ctx.exception), 'dooooom') if __name__ == '__main__': unittest.main()这里
test_bar是标准的测试方法,类级别的补丁会自动应用到这个方法的执行过程中,测试能正常捕获到预期的异常。
内容的提问来源于stack exchange,提问作者sparrowt

