|
@@ -0,0 +1,111 @@
|
|
|
|
|
+# MCP Python Gateway 100% 覆盖率设计
|
|
|
|
|
+
|
|
|
|
|
+## 背景
|
|
|
|
|
+
|
|
|
|
|
+Python Gateway 当前执行:
|
|
|
|
|
+
|
|
|
|
|
+```powershell
|
|
|
|
|
+python -m coverage run -m unittest discover -s tests -p "test_*.py"
|
|
|
|
|
+python -m coverage report -m
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+全量 `297` 个测试通过,但 `.coveragerc` 启用了语句和分支覆盖,当前 TOTAL 仅为
|
|
|
|
|
+`93.63%`。报告包含 1153 条语句和 418 条分支,其中缺少 52 条语句、48 条分支,
|
|
|
|
|
+共有 9 个生产文件未达到 100%。
|
|
|
|
|
+
|
|
|
|
|
+## 目标
|
|
|
|
|
+
|
|
|
|
|
+- 保持现有 `.coveragerc` 的 `source`、`omit`、`branch=True` 和报告口径不变。
|
|
|
|
|
+- 所有纳入统计的非空生产文件逐个达到 `100.00%`。
|
|
|
|
|
+- TOTAL 达到 `100.00%`,并通过 `coverage report --fail-under=100`。
|
|
|
|
|
+- 全量 unittest 保持通过,测试不依赖真实 Redis、外部 HTTP 服务或长期运行线程。
|
|
|
|
|
+- 不覆盖、不回退当前工作区已有的单号元数据和测试改动。
|
|
|
|
|
+
|
|
|
|
|
+## 不采用的方案
|
|
|
|
|
+
|
|
|
|
|
+### 扩大 omit 或添加 pragma
|
|
|
|
|
+
|
|
|
|
|
+不通过 `.coveragerc omit`、`exclude_lines` 或 `# pragma: no cover` 隐藏当前生产代码
|
|
|
|
|
+缺口。这会改变统计边界,无法证明现有代码路径经过测试。
|
|
|
|
|
+
|
|
|
|
|
+### 为覆盖率改写业务逻辑
|
|
|
|
|
+
|
|
|
|
|
+当前函数级报告未发现必须重构才能触达的代码。默认只修改测试;若实施中证明某条
|
|
|
|
|
+分支结构上不可达,应暂停并重新评审,而不是直接修改生产逻辑或排除该分支。
|
|
|
|
|
+
|
|
|
|
|
+## 实施结构
|
|
|
|
|
+
|
|
|
|
|
+### 第一批:叶子模块和数据边界
|
|
|
|
|
+
|
|
|
|
|
+| 生产文件 | 测试文件 | 覆盖重点 |
|
|
|
|
|
+|----------|----------|----------|
|
|
|
|
|
+| `tools/query_order_exact.py` | `tests/test_query_order_exact_tool.py` | 非法 scalar ID、逗号字符串 ID 列表、字符串列表去重回边 |
|
|
|
|
|
+| `services/token_store.py` | `tests/test_token_store_coverage.py` | 无目录文件、延迟读取、已删除文件清理、bytes 请求、非法 Redis 行 |
|
|
|
|
|
+| `services/gateway_session_store.py` | `tests/test_gateway_session_store_unit.py` | 不存在 session 的 touch |
|
|
|
|
|
+| `config.py` | `tests/test_config_compat.py` | timeout 环境变量优先级、无效 dotenv 行、带引号值和循环回边 |
|
|
|
|
|
+
|
|
|
|
|
+这一批不改生产代码,只补可观察的输入、返回值、异常和依赖调用断言。
|
|
|
|
|
+
|
|
|
|
|
+### 第二批:Gateway 应用和 CLI
|
|
|
|
|
+
|
|
|
|
|
+| 生产文件 | 测试文件 | 覆盖重点 |
|
|
|
|
|
+|----------|----------|----------|
|
|
|
|
|
+| `app.py` | `tests/test_app_coverage.py` | 注册工具名称、动态列表错误、request ID、缺少刷新客户端、public 启动、CLI 必填/可选参数及最终防御分支 |
|
|
|
|
|
+
|
|
|
|
|
+`serve-public` 使用 mock 替换 Redis client、session store、public app 和 server 入口;
|
|
|
|
|
+CLI 防御分支通过模拟参数解析结果触发,不启动真实服务。
|
|
|
|
|
+
|
|
|
|
|
+### 第三批:协议与公网服务
|
|
|
|
|
+
|
|
|
|
|
+| 生产文件 | 测试文件 | 覆盖重点 |
|
|
|
|
|
+|----------|----------|----------|
|
|
|
|
|
+| `mcp_protocol.py` | `tests/test_mcp_protocol_coverage.py` | 无 flush 输出、无 input schema、工具响应数据形态、错误 data/meta、空轨迹 tips |
|
|
|
|
|
+| `public_gateway.py` | `tests/test_public_gateway_unit.py` | 动态列表无效响应、不支持 touch_session 的 store |
|
|
|
|
|
+| `public_server.py` | `tests/test_public_server_coverage.py` | input schema 归一化、启用限流、清理线程、KeyboardInterrupt 关闭 |
|
|
|
|
|
+
|
|
|
|
|
+HTTP server、线程和无限清理循环都使用 mock 控制。清理循环测试捕获
|
|
|
|
|
+`threading.Thread` 的 target,并让受控 `time.sleep` 抛出测试专用异常终止循环,不做
|
|
|
|
|
+真实等待。
|
|
|
|
|
+
|
|
|
|
|
+## 测试质量要求
|
|
|
|
|
+
|
|
|
|
|
+- 测试名称描述具体行为,不以“覆盖第 N 行”作为唯一目的。
|
|
|
|
|
+- 每个异常分支同时断言异常类型和关键消息。
|
|
|
|
|
+- 每个成功分支断言返回值或依赖调用参数,不能只调用代码而不验证结果。
|
|
|
|
|
+- mock 仅用于 Redis、socket、HTTP server、线程、时钟和 CLI 解析等外部边界。
|
|
|
|
|
+- 不添加只为测试存在的生产 API。
|
|
|
|
|
+- 每批完成后运行目标测试,再重新执行全量 coverage,依据新的 Missing 列继续收敛。
|
|
|
|
|
+
|
|
|
|
|
+## 验证流程
|
|
|
|
|
+
|
|
|
|
|
+每批执行:
|
|
|
|
|
+
|
|
|
|
|
+```powershell
|
|
|
|
|
+python -m unittest <本批目标测试模块>
|
|
|
|
|
+python -m coverage run -m unittest discover -s tests -p "test_*.py"
|
|
|
|
|
+python -m coverage report -m
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+最终验收:
|
|
|
|
|
+
|
|
|
|
|
+```powershell
|
|
|
|
|
+python -m coverage run -m unittest discover -s tests -p "test_*.py"
|
|
|
|
|
+python -m coverage report -m --fail-under=100
|
|
|
|
|
+git diff --check
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+验收标准:
|
|
|
|
|
+
|
|
|
|
|
+1. 全量 unittest 返回 0。
|
|
|
|
|
+2. 报告中每个非空生产文件为 `100.00%`。
|
|
|
|
|
+3. TOTAL 为 `100.00%`,Missing 为空。
|
|
|
|
|
+4. `.coveragerc` 的统计范围和分支覆盖设置未被放宽。
|
|
|
|
|
+5. 工作区原有单号工具改动保持完整。
|
|
|
|
|
+
|
|
|
|
|
+## 风险与处理
|
|
|
|
|
+
|
|
|
|
|
+- 覆盖率 100% 不等于业务逻辑绝对正确;测试仍以可观察行为和关键错误边界为主。
|
|
|
|
|
+- 线程/服务器测试若泄漏真实后台线程会导致套件不稳定,因此必须 mock `Thread.start`
|
|
|
|
|
+ 或捕获 target 后同步执行。
|
|
|
|
|
+- 分支覆盖可能在新增测试后暴露新的回边提示;以最新 `coverage report -m` 为准逐项
|
|
|
|
|
+ 处理,不通过删除有效断言或放宽配置收尾。
|