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
相关产品推荐
相关产品推荐

