如何让@classmethod的mock.patch在整个测试会话中生效?
如何在unittest中全局patch类方法避免重复操作?
我希望对一个@classmethod执行mock.patch,仅调用一次patch.object而非在每个测试用例中重复执行。
当前实现方式
目前必须在每个测试方法内通过with语句调用patch.object,示例代码如下:
class MyClass(): @classmethod def print_hello(cls): print("hello from the real MyClass.print_hello") def do_something(self): pass def mock_print_hello(_cls): print("hello from the patched mock_print_hello") class TestMyClass(unittest.TestCase): def test_init(self): with mock.patch.object(MyClass, "print_hello", new_callable=mock_print_hello) as patch: MyClass.print_hello() MyClass() def test_do_something(self): with mock.patch.object(MyClass, "print_hello", new_callable=mock_print_hello) as patch: MyClass.print_hello() MyClass().do_something()
尝试的无效实现
我尝试在setUpClass中执行patch,但该patch无法在测试方法中生效,测试仍会调用原类方法,示例代码如下:
class MyClass(): @classmethod def print_hello(cls) : print("hello from the real MyClass.print_hello") def do_something(self): pass def mock_print_hello(_cls): print("hello from the patched mock_print_hello") class TestMyClass(unittest.TestCase): @classmethod def setUpClass(cls): # this patch will not remain after setUpClass returns patch = mock.patch.object(MyClass, "print_hello", new_callable=mock_print_hello) def test_init(self): # this calls the real MyClass.print_hello, not mock_print_hello MyClass.print_hello() MyClass() def test_do_something(self): # this calls the real MyClass.print_hello, not mock_print_hello MyClass.print_hello() MyClass().do_something()
解决方案
之前的无效实现问题在于:只创建了patch对象,但没有调用start()方法激活补丁,所以原方法不会被替换。以下两种方法可以实现全局生效的patch:
方法一:利用setUpClass和tearDownClass手动管理补丁生命周期
在测试类的初始化阶段启动补丁,测试全部完成后停止补丁,这样整个测试类的所有用例都会使用补丁:
import unittest from unittest import mock class MyClass(): @classmethod def print_hello(cls): print("hello from the real MyClass.print_hello") def do_something(self): pass def mock_print_hello(_cls): print("hello from the patched mock_print_hello") class TestMyClass(unittest.TestCase): @classmethod def setUpClass(cls): # 创建补丁并启动 cls.patch = mock.patch.object(MyClass, "print_hello", new_callable=mock_print_hello) cls.patch.start() @classmethod def tearDownClass(cls): # 测试类所有用例执行完毕后停止补丁 cls.patch.stop() def test_init(self): MyClass.print_hello() # 调用mock方法 MyClass() def test_do_something(self): MyClass.print_hello() # 调用mock方法 MyClass().do_something() if __name__ == '__main__': unittest.main()
方法二:用装饰器直接装饰测试类
使用@mock.patch.object装饰整个测试类,unittest会自动帮你管理补丁的启动和停止,所有测试方法都会自动应用该补丁:
import unittest from unittest import mock class MyClass(): @classmethod def print_hello(cls): print("hello from the real MyClass.print_hello") def do_something(self): pass def mock_print_hello(_cls): print("hello from the patched mock_print_hello") @mock.patch.object(MyClass, "print_hello", new_callable=mock_print_hello) class TestMyClass(unittest.TestCase): def test_init(self, mock_patch): MyClass.print_hello() # 调用mock方法 MyClass() def test_do_something(self, mock_patch): MyClass.print_hello() # 调用mock方法 MyClass().do_something() if __name__ == '__main__': unittest.main()
内容的提问来源于stack exchange,提问作者JamesThomasMoon
相关产品推荐
相关产品推荐

