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

Python测试派生类时如何完全模拟基类?

问题:测试Python派生类时完全模拟基类,避免调用基类__init__

我需要测试Python中一个派生类的方法,但基类ComplexAnnoyingBaseClass的__init__方法在测试场景下实现不佳,希望完全模拟该基类,让派生类MyDerivedClass继承模拟对象而非原基类。

类的简化示例:

class ComplexAnnoyingBaseClass:
    def __init__(self):
        print("do not execute this class in the unit test")
    def get_value_x(self):
        return 4
    def get_value_y(self):
        return 5

def calculate_value(x, y):
    return x * y

class MyDerivedClass(ComplexAnnoyingBaseClass):
    def get_value(self, min_x, min_y):
        value = 0
        x = self.get_value_x()
        y = self.get_value_y()
        if x > min_x and y > min_y:
            value = calculate_value(x, y)
        return value

我尝试了两种测试方式均失败:测试时打印了"do not execute"信息,且my_instance.get_value(1,1)返回20而非预期的6。

第一种测试代码:

import pytest
from unittest.mock import patch, Mock

from server.example_code import (
    ComplexAnnoyingBaseClass,
    MyDerivedClass
)

def test_get_value():
    # Patch the base class with a mock object
    with patch('server.example_code.ComplexAnnoyingBaseClass',
               spec=MyDerivedClass) as base_class_mock:
        # Create a mock instance of the derived class
        my_instance = MyDerivedClass()

        # Mock the get_value_x() and get_value_y() methods
        base_class_mock.get_value_x.return_value = 2
        base_class_mock.get_value_y.return_value = 3

        # Test your code here
        result = my_instance.get_value(1, 1)
        assert result == 6

第二种测试代码:

def test_get_value():
    # Create a mock instance of ComplexAnnoyingBaseClass
    base_class_mock = Mock()
    base_class_mock.get_value_x.return_value = 2
    base_class_mock.get_value_y.return_value = 3

    # Patch the base class with the mock object
    with patch('server.example_code.ComplexAnnoyingBaseClass',
            return_value=base_class_mock):
        # Create an instance of MyDerivedClass
        my_instance = MyDerivedClass()

        # Test your code here
        result = my_instance.get_value(1, 1)
        assert result == 6

请问如何完全模拟基类,使其__init__方法在测试时不被调用?


解决方案

问题根源

你之前的测试失败,核心原因是**MyDerivedClass在定义时已经绑定了原基类ComplexAnnoyingBaseClass**,后续patch基类的操作不会改变已定义派生类的继承关系。实例化MyDerivedClass时,依然会调用原基类的__init__,且派生类会从原基类继承方法,而非你设置的Mock方法。

正确实现方式1:动态替换派生类的基类

直接修改MyDerivedClass的__bases__属性,让它临时继承Mock对象,这样实例化时不会触发原基类的__init__,且能完全控制基类方法的返回值。

测试代码示例

import pytest
from unittest.mock import Mock, patch
from server.example_code import MyDerivedClass, calculate_value

def test_get_value():
    # 保存原基类,测试完成后恢复,避免影响其他用例
    original_bases = MyDerivedClass.__bases__
    
    try:
        # 创建Mock基类,模拟需要的方法返回值
        mock_base = Mock()
        mock_base.get_value_x.return_value = 2
        mock_base.get_value_y.return_value = 3
        
        # 替换派生类的基类为Mock对象
        MyDerivedClass.__bases__ = (mock_base,)
        
        # 实例化派生类,此时不会执行原基类的__init__
        my_instance = MyDerivedClass()
        
        # 执行测试
        result = my_instance.get_value(1, 1)
        assert result == 6
        
        # 可选:验证calculate_value是否被正确调用
        with patch('server.example_code.calculate_value') as calc_mock:
            calc_mock.return_value = 6
            my_instance.get_value(1,1)
            calc_mock.assert_called_once_with(2,3)
    finally:
        # 恢复派生类的原基类
        MyDerivedClass.__bases__ = original_bases

正确实现方式2:patch派生类的__init__跳过基类初始化

如果你不想修改基类继承关系,也可以直接patch派生类的__init__方法,避免它调用原基类的__init__,然后给实例绑定Mock方法:

def test_get_value_alternative():
    with patch.object(MyDerivedClass, '__init__', return_value=None) as mock_init:
        my_instance = MyDerivedClass()
        # 给实例绑定Mock方法
        my_instance.get_value_x = Mock(return_value=2)
        my_instance.get_value_y = Mock(return_value=3)
        
        result = my_instance.get_value(1,1)
        assert result ==6
        # 验证原基类__init__未被调用
        mock_init.assert_called_once()

这种方式更直接,适合只需要跳过基类初始化的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 07:37:10