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

Python如何通过修改sys.modules模拟`module.module.Class`类路径实现单元测试?

问题根因

你当前报错的核心原因是__import__导入多层级子模块的逻辑不符合预期:默认调用__import__('a.b.c')时返回的是顶层的a模块,而非你需要的c子模块。你代码中赋值给sys.modules['firebase_admin.messaging']的对象实际是顶层的tests模块,自然找不到你定义的Aps类。

修复方案

方案1:修正现有手动替换模块的写法

仅需调整tests.py中导入mock模块的逻辑,给__import__增加fromlist参数即可正确获取到messaging子模块:

import sys

# 正确获取mock的firebase_admin根模块
firebase_admin_module = __import__('tests.mock_firebase_admin', fromlist=[''])
sys.modules['firebase_admin'] = firebase_admin_module

# 正确获取mock的messaging子模块
messaging = __import__('tests.mock_firebase_admin.messaging', fromlist=[''])
sys.modules['firebase_admin.messaging'] = messaging
setattr(firebase_admin_module, 'messaging', messaging)

修改后业务代码中调用firebase_admin.messaging.Aps()就会正常触发你自定义的mock类构造逻辑。

方案2:使用unittest.mock简化实现(更推荐)

不需要手动维护sys.modules的替换逻辑,直接通过patch装饰器/上下文管理器替换目标模块的依赖即可,示例如下:

from unittest import mock
from tests.mock_firebase_admin import messaging as mock_messaging

# 直接替换业务代码中引用的firebase_admin.messaging模块
@mock.patch('app.cannot_edit_this_file.firebase_admin.messaging', new=mock_messaging)
def test_your_business_logic():
    # 此处执行业务代码,Aps会自动使用你定义的mock类
    ...
注意事项

避免可变默认参数坑:你当前mock的Aps类中custom_data={}属于可变默认参数,多次实例化时会复用同一个字典对象,建议调整为custom_data=None,在__init__内部初始化空字典:

class Aps():
    def __init__(self,
                 alert=None,
                 content_available=True,
                 sound="default",
                 custom_data=None):
        custom_data = custom_data if custom_data is not None else {}
        print("Hello from mock Aps constructor!")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 10:15:05