ForcePilot/backend/test/unit/channels/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

153 lines
6.1 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 限界上下文单元测试跨层通用 fixture。
本文件提供横跨 core / application / adapters / plugins 各层复用的被驱动
端口桩LoggerPort / ConfigPort / CachePort / EventPublisherPort /
TracerPort。桩使用 ``unittest.mock`` 的 ``MagicMock`` / ``AsyncMock``
不实现真实逻辑;端口方法签名以 ``yuxi.channels.contract.ports.driven``
下的 Protocol 为准。
注意LoggerPort / TracerPort 的方法在端口协议中均为 ``async def``,因此
此处使用 ``MagicMock(spec=...)`` —— MagicMock 会自动为 async 方法生成
AsyncMock可 ``await``),与端口协议保持一致。单文件独有的 helper 应保
留在对应测试文件内(见 testing-guidelines.md
"""
from __future__ import annotations
from unittest.mock import AsyncMock, MagicMock
import pytest
from yuxi.channels.contract.ports.driven.cache_port import CachePort
from yuxi.channels.contract.ports.driven.config_port import ConfigPort
from yuxi.channels.contract.ports.driven.event_publisher_port import (
EventPublisherPort,
)
from yuxi.channels.contract.ports.driven.logger_port import LoggerPort
from yuxi.channels.contract.ports.driven.tracer_port import TracerPort
from yuxi.channels.core.service.config_manager import ConfigManager
@pytest.fixture
def fake_logger() -> LoggerPort:
"""LoggerPort 桩。
``MagicMock(spec=LoggerPort)`` 自动为 ``log`` / ``debug`` / ``info`` /
``warn`` / ``error`` / ``exception`` 生成 AsyncMock可 ``await``
默认返回 None。需要断言调用参数时直接使用对应方法的 ``assert_*``。
"""
return MagicMock(spec=LoggerPort)
@pytest.fixture
def fake_config() -> ConfigPort:
"""ConfigPort 桩,``get`` 默认返回 None``update`` 默认返回 None。"""
mock = AsyncMock(spec=ConfigPort)
mock.get.return_value = None
mock.update.return_value = None
return mock
@pytest.fixture
def fake_config_manager() -> ConfigManager:
"""ConfigManager 桩。
``AsyncMock(spec=ConfigManager)`` 自动为 ``update`` / ``updateInternal``
/ ``rollback`` 等 async 方法生成 AsyncMock。``update`` /
``updateInternal`` 默认返回 None调用方按需覆盖返回值。
"""
mock = AsyncMock(spec=ConfigManager)
mock.update.return_value = None
mock.updateInternal.return_value = None
return mock
@pytest.fixture
def fake_cache() -> CachePort:
"""CachePort 桩,预设常用方法返回值。
``get`` 返回 None``set`` / ``delete`` / ``expire`` /
``acquireAdvisoryLock`` / ``releaseAdvisoryLock`` / ``ping`` 返回 True
``incr`` 返回 1。
"""
mock = AsyncMock(spec=CachePort)
mock.get.return_value = None
mock.set.return_value = True
mock.delete.return_value = True
mock.incr.return_value = 1
mock.expire.return_value = True
mock.acquireAdvisoryLock.return_value = True
mock.releaseAdvisoryLock.return_value = True
mock.ping.return_value = True
return mock
@pytest.fixture
def fake_event_publisher() -> EventPublisherPort:
"""EventPublisherPort 桩,``publish`` 默认返回 None。"""
mock = AsyncMock(spec=EventPublisherPort)
mock.publish.return_value = None
return mock
@pytest.fixture
def fake_tracer() -> TracerPort:
"""TracerPort 桩。
``MagicMock(spec=TracerPort)`` 自动为 ``startSpan`` / ``endSpan`` /
``getCurrentTrace`` 生成 AsyncMock可 ``await``)。``startSpan`` 默认
返回 Span-like MagicMock``endSpan`` 返回 None``getCurrentTrace``
返回 Option-like MagicMock调用方可按需覆盖。
"""
mock = MagicMock(spec=TracerPort)
mock.startSpan.return_value = MagicMock()
mock.endSpan.return_value = None
mock.getCurrentTrace.return_value = MagicMock()
return mock
@pytest.fixture
def fake_plugin_host() -> MagicMock:
"""PluginHost 桩(跨层共享)。
``MagicMock()`` 模拟 ``PluginHost`` 协议
``yuxi.channels.contract.plugin.entry.PluginHost``
- 所有 ``getXxxPort()`` 返回 ``MagicMock`` 桩(调用方可覆盖为带
``spec`` 的端口桩,如 ``host.getLoggerPort.return_value = fake_logger``
- ``registerAdapter()`` / ``registerStageSlot()`` / ``registerEventSubscription()``
/ ``registerConfigSource()`` / ``registerMatchTier()`` / ``registerMatcher()``
返回 ``None``
- ``publishEvent`` 为 ``AsyncMock``(可 ``await``),返回 ``None``。
本 fixture 提升至 channels 限界上下文根 conftest供 application/lifecycle
与 plugins 各层测试复用(避免在子目录 conftest 重复定义)。
"""
host = MagicMock()
# 端口获取:返回 MagicMock 桩,调用方可覆盖为带 spec 的端口桩
host.getConfigPort.return_value = MagicMock()
host.getLoggerPort.return_value = MagicMock()
host.getPersistencePort.return_value = MagicMock()
host.getCachePort.return_value = MagicMock()
host.getTracerPort.return_value = MagicMock()
host.getQueuePort.return_value = MagicMock()
host.getConversationPort.return_value = MagicMock()
host.getAgentRunPort.return_value = MagicMock()
host.getIdentityResolverPort.return_value = MagicMock()
host.getChannelAccountRepositoryPort.return_value = MagicMock()
host.getChannelSessionRepositoryPort.return_value = MagicMock()
host.getPairingRepositoryPort.return_value = MagicMock()
host.getAuditLogRepositoryPort.return_value = MagicMock()
host.getOutboxRepositoryPort.return_value = MagicMock()
host.getUserIdentityRepositoryPort.return_value = MagicMock()
host.getIdempotencyRepositoryPort.return_value = MagicMock()
host.getPersistenceHealthPort.return_value = MagicMock()
# 扩展点注册:返回 None
host.registerAdapter.return_value = None
host.registerStageSlot.return_value = None
host.registerEventSubscription.return_value = None
host.registerConfigSource.return_value = None
host.registerMatchTier.return_value = None
host.registerMatcher.return_value = None
# 事件发布async def使用 AsyncMock
host.publishEvent = AsyncMock(return_value=None)
return host