ForcePilot/backend/test/unit/channels/plugins/wecom/conftest.py
Kris 08617091dc refactor: 整理项目包结构与导入路径
- 新增多个业务域的__init__.py模块文件,规范包导出结构
- 调整多个DTO文件的导入路径,统一模块组织方式
- 移除测试文件中多余的空行与导入语句
- 优化部分业务模块的包层级划分
2026-07-18 02:04:03 +08:00

123 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.shared.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