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

如何在Python中Patch整个类、跳过__init__并自定义方法返回值

Mock Python类时跳过__init__并自定义方法返回值

问题描述

尝试在Python中patch整个类,跳过包含测试时不想执行的API调用的__init__方法,同时为类的方法定义返回值,请问是否有可行的实现方式?

相关代码

Module.py

class MyClass():
    
    def __init__(self):
        # 测试时不想执行的API调用
        print("This shouldn't print in tests")
        
    def my_method(self, a, b):
        return a + b
    
a = MyClass()
a.my_method(1,2)

原尝试测试代码(test_class.py)

import unittest as test
from unittest.mock import MagicMock, patch

from module import MyClass

class TestClass(test.TestCase):

    # @patch("module.MyClass") # 原以为完全不生效
    @patch("module.MyClass.__new__") # 仍会调用__init__
    def test_my_class(self, mock_class: MagicMock):

        mock_class.return_value.my_method.return_value = 99
        
        my_class = MyClass()
        self.assertEqual(my_class.my_method(1,1), 99)
        
test.main()

尝试patch MyClass.__new__后仍会触发__init__,希望得到其他实现方式(刚接触mock和patch,欢迎指出忽略的要点)。


解决方案

方案1:直接patch整个类(最简洁高效)

当patch整个类时,原类会被替换为MagicMock,调用类构造方法时不会执行原__init__代码,同时可以轻松配置方法返回值。

修改后的测试代码:

import unittest as test
from unittest.mock import MagicMock, patch

from module import MyClass

class TestClass(test.TestCase):

    @patch("module.MyClass")
    def test_my_class(self, mock_class: MagicMock):
        # 获取mock类的实例对象(调用MyClass()会返回该实例)
        mock_instance = mock_class.return_value
        # 配置my_method的返回值
        mock_instance.my_method.return_value = 99
        
        my_class = MyClass()
        # 验证返回值符合预期
        self.assertEqual(my_class.my_method(1,1), 99)
        # 可选:验证类被实例化过一次
        mock_class.assert_called_once()
        
test.main()

原尝试失败原因:
你之前标注@patch("module.MyClass")不生效,是因为没有正确配置mock_class.return_value的方法返回值。按上述方式配置后,原类的__init__不会执行(不会打印测试中不该出现的内容),同时方法返回值会按设定生效。

方案2:单独patch __init__方法(保留原类其他方法逻辑)

如果只想跳过__init__,但保留类中其他方法的原有实现(或部分mock),可以单独patch__init__:

import unittest as test
from unittest.mock import patch, MagicMock

from module import MyClass

class TestClass(test.TestCase):

    @patch.object(MyClass, '__init__', return_value=None)
    @patch.object(MyClass, 'my_method')
    def test_my_class(self, mock_my_method, mock_init):
        # 配置my_method的返回值
        mock_my_method.return_value = 99
        
        my_class = MyClass()
        self.assertEqual(my_class.my_method(1,1), 99)
        # 验证__init__被调用但原代码未执行
        mock_init.assert_called_once()
        
test.main()

方案3:使用spec参数创建贴近原类的mock

如果需要mock类同时保留原类的方法签名,避免调用不存在的方法,可以用spec参数:

import unittest as test
from unittest.mock import patch

from module import MyClass

class TestClass(test.TestCase):

    @patch("module.MyClass", spec=MyClass)
    def test_my_class(self, mock_class):
        mock_class.return_value.my_method.return_value = 99
        
        my_class = MyClass()
        self.assertEqual(my_class.my_method(1,1), 99)
        # 调用原类不存在的方法会抛出AttributeError,符合原类结构
        with self.assertRaises(AttributeError):
            my_class.non_existent_method()
        
test.main()

关键要点提醒

  • patch的目标位置:必须patch被测试代码中类的引用位置,而非测试文件中导入的类。比如测试文件中from module import MyClass,则patch"module.MyClass"才是正确的,因为这是原模块中的类定义位置。
  • __new__与__init__的关系:__new__负责创建实例,__init__负责初始化实例。即使patch了__new__,如果返回的是类的实例,Python仍会自动调用__init__,这就是你之前patch__new__仍触发__init__的原因。
  • MagicMock的层级:patch类后,mock_class是类的mock对象,mock_class.return_value是实例的mock对象,需要给实例的方法配置返回值。

内容的提问来源于stack exchange,提问作者anthony_brother

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 16:35:05