diff --git a/AGENTS.md b/AGENTS.md index 5f7d54e..f527f26 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -243,6 +243,34 @@ focus-harness ← focus-core, focus-json | **集成测试** | `crates//tests/*.rs` | 跨模块的端到端(如 agent 循环跑完一轮) | | **mock 驱动** | `crates/focus-core/tests/agent_loop.rs` 内联 `MockProvider` | 用预设的 `StreamEvent` 序列驱动循环;仅当前单一测试文件使用时内联,多文件共享时抽为独立测试工具 crate | +#### 5.1.1 测试位置硬性规则(所有 crate 统一遵守) + +- **所有测试用例**(单元 + 集成)都必须放在 `crates//tests/` 下,**禁止**在 + `src/**` 里写 `#[cfg(test)] mod tests` 内联测试模块。`tests/` 下的文件是独立 crate, + 只能访问被测 crate 的**公开 API**。 +- 当测试需要触及**内部实现**时,二选一: + 1. **通过公开 API 测试**(优先):如 provider 的请求体翻译用 mock transport + 录制请求后断言其 JSON,而不是直接测私有 builder 函数; + 2. **提升为 `pub`**:确有必要公开的内部组件(如 `ChunkedDecoder`、 + `days_to_ymd`)提升为 `pub` 并写完整文档注释,测试放到 `tests/` 中。 +- **唯一例外**:`#[cfg(test)]` 的**测试基础设施**(非测试用例本身,如 + `focus-transport/src/tls.rs` 中仅测试用的放行式 TLS 配置)允许留在 `src/`。 + +#### 5.1.1 Rule: where tests must live (applies to every crate) + +- **All test cases** (unit + integration) must live under `crates//tests/`; + inline `#[cfg(test)] mod tests` inside `src/**` is **forbidden**. Files under + `tests/` are separate crates and can only see the tested crate's **public API**. +- When a test must touch **internals**, pick one of: + 1. **Test through the public API** (preferred): e.g. provider request-body + translation is asserted on the request recorded by a mock transport, not on + a private builder function; + 2. **Promote to `pub`**: genuinely useful internals (e.g. `ChunkedDecoder`, + `days_to_ymd`) become `pub` with full doc comments, tested from `tests/`. +- **Only exception**: `#[cfg(test)]` **test infrastructure** (not test cases — + e.g. the test-only permissive TLS config in `focus-transport/src/tls.rs`) may + stay in `src/`. + ### 5.2 TDD 流程 实现任何功能/修复前: