如何Mock类实例属性?Mock Meta.metadata触发AttributeError问题排查
如何Mock类的实例属性(而非类属性)
我之前成功Mock过类函数,但无法Mock类的实例属性。以下是目标类代码:
# 文件路径:exchanges.exchange class Meta: required_fields = ['security_file', 'data_file_group', 'mic'] def __init__(self, exchange): self.exchange = exchange self.metadata = {} # 证券代码到元数据字典的映射 self.db_write = exchange.db_write
我需要Mock上述代码中的self.metadata属性,于是在测试代码中编写了如下内容:
@mock.patch('exchanges.exchange.Meta.metadata', return_value = {('10080', '20230104'): {'price_type': 'U', 'isin': 'data_file_group': 'itchebbo', 'security_file': '10080_20230104.h5'}}) def test_check_valid_currency_no_ccy_no_Bloomberg(): # 测试逻辑...
运行测试时触发错误:
AttributeError: <class 'exchanges.exchange.Meta'> does not have the attribute 'metadata'
我疑惑mock.patch是否仅适用于Mock函数和类,而非类实例属性,希望能成功Mock Meta的metadata实例属性。
问题原因
你当前的写法是试图Mock类属性Meta.metadata,但metadata是在__init__方法中定义的实例属性——类本身并没有这个属性,只有类的实例才会在初始化后拥有该属性,因此报错。
解决方案
针对实例属性的Mock需要在实例层面操作,以下是几种可行方法:
方法1:直接替换实例属性
如果测试代码中会主动创建Meta实例,初始化后直接替换其metadata属性即可:
def test_check_valid_currency_no_ccy_no_Bloomberg(): # 创建exchange的Mock对象(满足Meta初始化参数要求) mock_exchange = Mock() # 初始化Meta实例 meta_instance = Meta(mock_exchange) # 替换实例的metadata为预设值 meta_instance.metadata = { ('10080', '20230104'): { 'price_type': 'U', 'isin': '', 'data_file_group': 'itchebbo', 'security_file': '10080_20230104.h5' } } # 执行后续测试逻辑 # ...
方法2:Mock__init__方法预设属性
如果希望实例创建时自动带有预设的metadata,可以Mock类的__init__方法,手动模拟属性赋值:
@mock.patch('exchanges.exchange.Meta.__init__') def test_check_valid_currency_no_ccy_no_Bloomberg(mock_init): mock_exchange = Mock() # 自定义__init__的执行逻辑 def init_side_effect(exchange): self = mock_init.return_value self.exchange = exchange # 直接设置预设的metadata self.metadata = { ('10080', '20230104'): { 'price_type': 'U', 'isin': '', 'data_file_group': 'itchebbo', 'security_file': '10080_20230104.h5' } } self.db_write = exchange.db_write mock_init.side_effect = init_side_effect # 创建实例,此时metadata已被预设 meta_instance = Meta(mock_exchange) # 执行测试逻辑 # ...
方法3:用patch.object替换已有实例的属性
如果被测试代码中已经存在Meta实例,可通过patch.object临时替换其metadata:
def test_check_valid_currency_no_ccy_no_Bloomberg(): # 假设被测试代码中已有一个Meta实例target_meta target_meta = Meta(Mock()) # 上下文管理器中替换属性 with mock.patch.object(target_meta, 'metadata', new={ ('10080', '20230104'): { 'price_type': 'U', 'isin': '', 'data_file_group': 'itchebbo', 'security_file': '10080_20230104.h5' } }): # 此上下文中target_meta的metadata为预设值 # 执行测试逻辑 # ...
总结
mock.patch并非只能Mock函数和类,关键是要区分类属性和实例属性:类属性直接属于类,而实例属性仅存在于类的实例中。针对实例属性的Mock,需要在实例创建后操作,或通过Mock初始化方法来预设属性。
内容的提问来源于stack exchange,提问作者fhd
相关产品推荐
相关产品推荐

