You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 10:23:17