# MCP Gateway 测试说明 本目录存放 MCP Gateway 的单元测试和集成测试,覆盖本地 stdio 模式、公网 HTTP 模式、Redis session、认证客户端、工具转发和安全工具函数。 ## 测试结构 ```text tests/ ├── test_rate_limiter.py # 简单滑动窗口限流 ├── test_gateway_session_store_unit.py # 公网 Gateway Redis session 存储 ├── test_request_context.py # 从 header、Bearer、cookie 解析 gateway_session_id ├── test_scoped_auth_client.py # 公网模式授权码换票客户端 ├── test_scoped_api_client.py # 公网模式工具转发客户端 ├── test_public_gateway_unit.py # PublicGatewayApp 业务路由和 session 校验 ├── test_security.py # session ID、hash、常量时间比较 ├── test_public_server_integration.py # HTTP 服务集成测试 ├── test_run_coverage.py # 覆盖率脚本回归测试 └── test_*.py # 既有本地 Gateway 测试 ``` ## 运行全部测试 ```powershell python -m unittest discover -s tests -p "test_*.py" ``` ## 运行指定测试文件 ```powershell python -m unittest tests.test_rate_limiter ``` ## 运行指定测试类 ```powershell python -m unittest tests.test_rate_limiter.TestSimpleRateLimiter ``` ## 运行指定测试方法 ```powershell python -m unittest tests.test_rate_limiter.TestSimpleRateLimiter.test_allows_requests_within_limit ``` ## 输出详细日志 ```powershell python -m unittest discover -s tests -p "test_*.py" -v ``` ## 覆盖范围 单元测试覆盖: - 限流器:滑动窗口、清理、多 key 隔离。 - Gateway session store:Redis CRUD、key hash、TTL。 - Request context:从 header、Authorization、cookie 解析 session,并验证优先级。 - Scoped auth client:授权码换票、session 持久化、错误处理。 - Scoped API client:工具调用、token 校验、header 组装。 - PublicGatewayApp:工具路由、session 校验、request_id 生成。 - Security utils:session ID 生成、SHA256 hash、常量时间比较。 集成测试覆盖: - HTTP `/health`。 - MCP `initialize`、`tools/list`、`tools/call`。 - 缺少 session 的错误响应。 - header、Bearer、cookie 三种 session 传递方式。 - 404 和未知方法处理。 ## 测试依赖 当前测试使用 Python 标准库: - `unittest` - `unittest.mock` - `http.client` - `threading` 不需要额外安装测试依赖。 ## 新增测试约定 - 文件名使用 `test_.py`。 - 测试类使用 `Test`。 - 测试方法使用 `test_`。 - 每个测试尽量只验证一个行为。 - Redis、HTTP 客户端等外部依赖使用 mock 或 fake 实现。 - 安全修复必须补回归测试,例如不能记录授权码、不能信任可伪造 header。 ## 常见问题 ### 集成测试提示 Connection refused HTTP 测试服务可能还未启动完成。可适当增加 `setUpClass` 中的等待时间: ```python sleep(1.0) ``` ### mock 断言异常 确认每个测试前重置 mock: ```python def setUp(self): self.mock_object.reset_mock() ``` ## 覆盖率报告 ### 快速开始 使用便捷脚本: ```powershell # 运行测试并生成所有覆盖率报告 python run_coverage.py # 运行并自动在浏览器中打开 HTML 报告 python run_coverage.py --open ``` ### 手动命令 如需手动生成覆盖率报告,需要额外安装 `coverage`: ```powershell pip install coverage # 运行测试并收集覆盖率数据 coverage run -m unittest discover -s tests -p "test_*.py" # 生成控制台报告 coverage report # 生成 HTML 报告 coverage html # 生成 XML 报告(用于 CI/CD) coverage xml ``` ### 报告类型 运行覆盖率测试后,会生成三种报告: 1. **控制台报告**:在终端显示,包含每个模块的覆盖率百分比 2. **HTML 报告**:交互式网页界面,位于 `htmlcov/index.html` - 显示逐行覆盖情况,颜色编码 - 点击文件可查看哪些行被执行 - 红色 = 未覆盖,绿色 = 已覆盖 3. **XML 报告**:机器可读格式,用于 CI/CD 工具(`coverage.xml`) ### 覆盖率指标说明 - **Stmts**: 可执行语句总数 - **Miss**: 未执行的语句数 - **Branch**: 分支总数(if/else 条件) - **BrPart**: 部分覆盖的分支数 - **Cover**: 总体覆盖率百分比 ### 当前覆盖率 (2026-07-08) | 模块 | 覆盖率 | |------|----------| | **新增模块(Public 模式)** | | | `constants.py` | 100% ✅ | | `services/api_client.py` | 100% ✅ | | `services/gateway_session_store.py` | 100% ✅ | | `services/scoped_api_client.py` | 100% ✅ | | `services/scoped_auth_client.py` | 100% ✅ | | `tools/query_track.py` | 100% ✅ | | `utils/rate_limiter.py` | 100% ✅ | | `utils/security.py` | 100% ✅ | | `services/request_context.py` | 97.37% ✅ | | `public_gateway.py` | 95.31% ✅ | | `services/auth_client.py` | 94.59% ✅ | | `config.py` | 93.18% ✅ | | **现有模块** | | | `public_server.py` | 83.47% | | `app.py` | 74.58% | | `tools/query_order.py` | 80.95% | | `mcp_protocol.py` | 80.28% | | `tools/bind_auth_code.py` | 75.00% | | `services/token_store.py` | 52.40% | | **总体** | **80.80%** ✅ | ### 覆盖率配置 覆盖率通过 `.coveragerc` 配置: - **源代码**: 项目根目录的所有 Python 文件 - **排除**: 测试文件、缓存、虚拟环境、覆盖率运行器 `run_coverage.py` - **分支覆盖**: 已启用(追踪 if/else 路径) - **报告精度**: 2 位小数 - **排除规则**: `# pragma: no cover` 注释、调试代码、`if __name__ == '__main__'` ### 提高覆盖率 对于低覆盖率的文件: 1. 在 HTML 报告中识别未覆盖的行 2. 编写测试来执行这些代码路径 3. 关注边界情况和错误处理 4. 继续补充主入口点(`app.py`)中 `serve-public` 和异常分支的集成测试 ### CI/CD 集成 GitHub Actions 工作流示例: ```yaml - name: Run tests with coverage run: | pip install coverage coverage run -m unittest discover -s tests -p "test_*.py" coverage report --fail-under=80 - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: file: ./coverage.xml ``` `coverage html` 会在 `htmlcov/` 目录生成 HTML 报告。