ForcePilot/backend/test/unit/channels/plugins/wecom/conftest.py
Kris 361dbe2149 test: 批量修复单元测试与集成测试用例的各类问题
本次提交修复了多个测试文件中的问题:
1.  为各管道测试类添加tracer_port属性初始化
2.  修复QQBot客户端关闭异常的错误类型匹配
3.  修正配对接口查询的状态值小写格式
4.  移除ChannelType枚举值的显式.value调用
5.  新增QQ常量的导出项与Instagram测试桩函数
6.  修复API接口返回值解析,正确访问data字段
7.  调整企业微信富文本消息的断言结构
8.  修正微信iLink的消息类型测试用例
9.  替换废弃的datetime.utc相关导入为UTC常量
10. 修复QQBot白名单适配器的返回值结构
11. 调整outbox工具的channel_msg_id处理逻辑
12. 新增多个适配器与服务的测试用例,覆盖异常降级、缓存处理等场景
13. 重构部分QQBot适配器的辅助函数测试,清理冗余代码
14. 修复微信iLink客户端的上传接口调用参数与缓存清理逻辑
15. 修正配置导出接口的敏感字段过滤与返回值结构
2026-07-09 04:23:07 +08:00

124 lines
4.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""channels plugins/wecom 层单元测试共享 fixture。
提供 ``fake_wecom_client`` 桩,模拟 ``WecomClient``
``yuxi.channels.plugins.wecom.wecom_client.WecomClient``。wecom 适配器
测试通过此桩注入客户端依赖,不发起真实 HTTP 请求。
另提供 ``_make_cache`` / ``_make_logger`` / ``_make_config`` 辅助工厂,
构造 ``CachePort`` / ``LoggerPort`` / ``ConfigPort`` 的 AsyncMock 桩,供
需要端口依赖的测试按需调用。
桩使用 ``AsyncMock()``,预设主要方法返回值,调用方可按需覆盖。方法签名
以 ``WecomClient`` 实现为准。单文件独有的 helper 应保留在对应测试文件内
(见 testing-guidelines.md
"""
from __future__ import annotations
from unittest.mock import AsyncMock
import pytest
from yuxi.channels.contract.dtos.option import Nothing
@pytest.fixture
def fake_wecom_client() -> AsyncMock:
"""WecomClient 桩。
``AsyncMock()`` 模拟 ``WecomClient``,预设主要方法返回值:
- ``send_message`` / ``send_kf_message`` / ``recall_message`` /
``update_template_card`` 返回 ``{"msgid": "msg-1", "errcode": 0}``
- ``upload_media`` 返回 ``{"media_id": "media-1", "errcode": 0}``
- ``download_media`` 返回 ``b"fake-content"``
- ``get_access_token`` 返回 ``"fake-token"``
- 通讯录 / 客户联系 / 客服 / OAuth API 返回 ``{}``。
"""
client = AsyncMock()
# Token 管理
client.get_access_token.return_value = "fake-token"
client.verify_token.return_value = True
client.get_token_with_credentials.return_value = ("fake-token", 7200)
# 应用消息 API
client.send_message.return_value = {"msgid": "msg-1", "errcode": 0}
client.recall_message.return_value = {"msgid": "msg-1", "errcode": 0}
client.update_template_card.return_value = {"msgid": "msg-1", "errcode": 0}
# 资源上传/下载
client.upload_media.return_value = {"media_id": "media-1", "errcode": 0}
client.download_media.return_value = b"fake-content"
# 通讯录 API
client.get_user.return_value = {}
client.list_user_ids.return_value = {}
client.convert_to_openid.return_value = {}
# 客户联系 API
client.get_external_contact.return_value = {}
client.list_external_contacts.return_value = {}
client.list_group_chats.return_value = {}
client.get_group_chat.return_value = {}
client.unionid_to_external_userid.return_value = {}
# 微信客服 API
client.send_kf_message.return_value = {"msgid": "msg-1", "errcode": 0}
client.list_kf_accounts.return_value = {}
# OAuth API
client.get_oauth_user_info.return_value = {}
client.get_user_detail.return_value = {}
client.get_oauth_user_info_with_credentials.return_value = {}
client.get_user_detail_with_credentials.return_value = {}
# 其它
client.get_api_domain_ip.return_value = {}
return client
def _make_cache(get_value=None) -> AsyncMock:
"""构造 CachePort 桩。
Args:
get_value: ``get`` 方法的返回值,默认为 ``Nothing()``。传入 ``Some(...)``
可模拟命中缓存。
Returns:
AsyncMock 模拟 ``CachePort````get`` 默认返回 ``Nothing()``
``set`` / ``delete`` 等方法为无返回值的 AsyncMock。
"""
cache = AsyncMock()
cache.get.return_value = Nothing() if get_value is None else get_value
cache.set.return_value = None
cache.delete.return_value = None
return cache
def _make_logger() -> AsyncMock:
"""构造 LoggerPort 桩。
Returns:
AsyncMock 模拟 ``LoggerPort````debug`` / ``info`` / ``warning`` /
``error`` 等方法为无返回值的 AsyncMock。
"""
logger = AsyncMock()
logger.debug.return_value = None
logger.info.return_value = None
logger.warning.return_value = None
logger.error.return_value = None
return logger
def _make_config(config_value=None) -> AsyncMock:
"""构造 ConfigPort 桩。
Args:
config_value: ``get`` 方法返回的 ConfigValue mock。默认构造一个带
``.value`` 属性的 mock调用方可传入自定义 mock 覆盖。
Returns:
AsyncMock 模拟 ``ConfigPort````get`` 默认返回带 ``.value`` 的
ConfigValue mock。
"""
config = AsyncMock()
if config_value is None:
cv = AsyncMock()
cv.value = None
config.get.return_value = cv
else:
config.get.return_value = config_value
return config