ForcePilot/backend/test/unit/channels/plugins/wecom/conftest.py

124 lines
4.4 KiB
Python
Raw Normal View History

"""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