内容
<h1 align="center">
<img src="assets/logo-mark.svg" width="40" height="40" alt="" valign="middle">
TestAtlas
</h1>
<p align="center">
<strong>一个可查询的、语义化的 .NET 测试自动化解决方案映射 —— 仅需一个 SQLite 文件。</strong>
</p>
<p align="center">
<em>零配置 · 无需 AI · 无需网络 · 确定性</em>
</p>
<p align="center">
<img alt="status" src="https://img.shields.io/badge/status-v0.1.1%20released-brightgreen">
<a href="https://www.nuget.org/packages/TestAtlas.Cli"><img alt="nuget" src="https://img.shields.io/nuget/v/TestAtlas.Cli?logo=nuget&label=NuGet&color=004880"></a>
<img alt="dotnet" src="https://img.shields.io/badge/.NET-8.0-512BD4?logo=dotnet&logoColor=white">
<img alt="output" src="https://img.shields.io/badge/output-SQLite-003B57?logo=sqlite&logoColor=white">
<img alt="mcp" src="https://img.shields.io/badge/MCP-ready-7C3AED">
<img alt="license" src="https://img.shields.io/badge/license-MIT-blue">
</p>
<p align="center">
<a href="#-quick-start">快速开始</a> ·
<a href="#-commands">命令</a> ·
<a href="#-use-it-from-an-ai-agent-mcp">MCP</a> ·
<a href="#-see-it-on-a-real-sample">示例</a> ·
<a href="#-keeping-the-map-fresh">保持更新</a> ·
<a href="#-roadmap">路线图</a>
</p>
---
## 它能做什么
TestAtlas 静态分析 .NET 测试自动化解决方案并生成一个**语义映射** —— `codemap.db`,一个单独的 SQLite 文件 —— 该文件捕获:
- **项目**及其依赖关系
- **Gherkin** 功能、场景和步骤
- **步骤定义**及其绑定(绑定 / 未绑定 / 模糊)
- **页面对象、API 客户端、帮助程序和测试类**
- 连接它们的所有**调用和用法关系**
…… 并将该映射转换为精确的答案:
| | 能力 | 你能得到什么 |
|:--:|---|---|
| 🔍 | **搜索** | FTS5 步骤定义和场景的全文搜索 — *"是否已经存在此步骤?"* |
| 💥 | **影响** | 爆破半径 — 更改类、方法、步骤或端点影响的场景 |
| 📊 | **报告** | 整个映射的自包含 HTML 钻取 |
| 🕸️ | **映射** | 自包含的项目依赖关系图(HTML) |
| 🔌 | **MCP** | 通过 stdio 将映射提供给 AI 代理 — 无需上下文填充 |
| 📈 | **统计** | 实体计数、类类型分解、绑定覆盖率、诊断 |
所有这些都是**离线、确定性和可复制的** —— 相同的输入,每次都会产生相同的映射。
> [!NOTE]
> 索引器规范使用 **"CodeMap"** 作为工具/CLI 的工作名称(`testatlas` 动词,`codemap.db` 输出)。存储库和产品是 **TestAtlas**。
---
## 为什么
大型测试自动化解决方案对于人类和 AI 代理来说都很难导航。要求代理自动执行新故事时,它看不到类似代码的位置、哪些步骤已经存在或解决方案遵循的约定。因此,它会复制步骤并错误地放置代码。
TestAtlas 对解决方案进行**一次**索引,并为人员和代理提供一个结构化的映射来回答这些问题 —— 确定性地,无需模型或网络调用。
---
## 🚀 快速开始
> **需要** [.NET SDK 8.0+](https://dotnet.microsoft.com/download)
从 NuGet 以全局 .NET 工具身份安装 CLI:
```bash
dotnet tool install --global TestAtlas.Cli
```
… 然后,从任何目录:
```bash
# 索引解决方案 → 生成 ./codemap.db
testatlas index path/to/YourSolution.sln
# 探索它
testatlas stats
testatlas search "login"
testatlas report # 写入 codemap.html
testatlas map # 写入 codemap-map.html
```
运行 `index` 时不带路径,TestAtlas 会自动发现当前目录中的单个 `.sln`/`.csproj`。映射会原子性地写入 `./codemap.db`。
<details>
<summary><b>或从源代码运行</b>(无需安装)</summary>
```bash
git clone https://github.com/Karzone/TestAtlas.git
cd TestAtlas
dotnet build TestAtlas.sln
dotnet run --project src/CodeMap.Cli -- index path/to/YourSolution.sln
```
</details>
---
## 📖 命令
| 命令 | 它能做什么 |
| --- | --- |
| `index [<path>]` | 分析 `.sln`/`.csproj` 并写入映射(默认为 `./codemap.db`)。 |
| `stats [<db>]` | 每个项目的实体计数、未绑定/模糊步骤、诊断。 |
| `search [<db>] <query>` | FTS5 步骤定义和场景的全文搜索。 |
| `impact [<db>] --class\|--method\|--step\|--endpoint <target>` | 爆破半径:更改实体影响的场景。 |
| `report [<db>]` | 写入映射的自包含 HTML 钻取。 |
| `map [<db>]` | 写入自包含的项目依赖关系图(HTML)。 |
| `validate [<db>]` | 检查文件是否为受支持的 TestAtlas 映射。 |
<details>
<summary><strong>选项和退出代码</strong></summary>
<br>
**`index`** `--output <file>` · `--config <file>` · `--include <glob>` (可重复)· `--exclude <glob>` (可重复)· `--verbose` · `--quiet`
**`search`** `--steps` (仅限步骤定义)· `--scenarios` (仅限场景)
**退出代码** `0` ok · `1` 已完成并带有警告 · `2` 致命错误 · `3` 参数错误
运行 `testatlas --help` 以获取完整的用法文本。
</details>
---
## 🧭 示例工作流
```bash
# 1. (可选)构建解决方案 — 参见下面的注释;映射无论如何都是相同的
dotnet build YourSolution.sln
# 2. 索引它
testatlas index YourSolution.sln --output atlas.db
# 3. 在编写新步骤之前 — 是否已经存在一个?
testatlas search atlas.db "add a product to the cart" --steps
# 4. 即将更改共享客户端 — 它会击中什么?
testatlas impact atlas.db --class ProductsApiClient
# 5. 共享可读快照
testatlas report atlas.db --html atlas.html
# 6. 查看项目之间的依赖关系
testatlas map atlas.db --html atlas-map.html
```
> [!NOTE]
> **您不需要在索引之前构建解决方案。** TestAtlas 是一个仅限语法的传递 —— 它从未要求 Roslyn 进行编译或语义模型 —— 因此索引会很好地进行。 Gherkin 从 `.feature` 文件本身中解析,步骤定义从源代码中的 `[Given]`/`[When]`/`[Then]` 属性读取;构建生成的代码后台(`*.feature.cs` 在 `obj/` 下)被故意**跳过**,因此构建只会产生索引器消耗的内容。 如果您出于自己的原因需要构建,请先构建。
---
## 🔌 从 AI 代理(MCP)使用它
TestAtlas 附带一个 MCP 服务器 — `testatlas-mcp` — 通过 stdio JSON-RPC 将映射提供给任何 MCP 感知客户端(Claude Code 和其他代理)。代理提出一个精确的问题,并从 `.db` 中获得一个确切的结构化答案 —— 而不是将源文件填充到其上下文窗口中。
它作为 **MCP 服务器包** 发布在 NuGet 上(`TestAtlas.Mcp`),因此 MCP 感知编辑器可以发现并启动它。 映射路径是**可选的** —— 服务器自动发现 `codemap.db`(或 `atlas.db`) 在工作目录中,或读取 `TESTATLAS_DB` 环境变量。
**Visual Studio / VS Code** (GitHub Copilot 代理模式)— 将其添加到您的 `.mcp.json`(`%USERPROFILE%\.mcp.json` 或 `<SolutionDir>\.mcp.json`):
```json
{
"servers": {
"testatlas": {
"type": "stdio",
"command": "dnx",
"args": ["TestAtlas.Mcp", "--yes"]
}
}
}
```
`dnx`(来自 .NET 10 SDK)按需获取并运行服务器 — 无需预安装。 从包含 `codemap.db` 的文件夹启动它,它会自动被选中;否则,请将路径作为最后一个参数附加。 在 Visual Studio 中,您还可以使用 **Tools picker → `+` → 添加自定义 MCP 服务器** 来为您编写此条目。
**Claude Code** — 安装全局工具并注册它:
```bash
dotnet tool install --global TestAtlas.Mcp
claude mcp add testatlas -- testatlas-mcp # 在 codemap.db 所在的目录中运行,或附加路径
claude mcp list # testatlas 行应为:✔ 已连接
```
默认情况下,服务器注册为**当前项目**( `--scope local`)。添加 `--scope user` 使其在您机器上的每个项目中可用,或 `--scope project` 与您的团队共享注册并提交 `.mcp.json`。
<details>
<summary><b>或从源代码运行</b>(无需安装)</summary>
```bash
dotnet build src/CodeMap.Mcp -c Release
# 在 Windows 上,二进制文件为 TestAtlas.Mcp.exe;在 macOS/Linux 上,它是 TestAtlas.Mcp
claude mcp add testatlas -- src/CodeMap.Mcp/bin/Release/net8.0/TestAtlas.Mcp.exe path/to/codemap.db
```
</details>
**公开的工具:**
- `stats` — 摘要计数:项目、类、方法、类类型分解、端点和边距计数。
- `impact` — 更改的爆破半径:给定类、方法、步骤定义或端点影响的场景。
- `search_steps` — 步骤定义的全文搜索(表达式文本 + 方法 + 类名)。
- `search_scenarios` — 场景的全文搜索(功能 + 场景名称 + 步骤文本 + 标签)。
- `list_endpoints` — 套件调用的 HTTP 端点,每个端点都有动词、路由和场景爆破半径(按最高到达次数排序)。
> [!IMPORTANT]
> MCP 客户端在**会话启动时**加载服务器。 如果您在会话中间注册服务器,请在 `testatlas` 工具出现之前重启您的 Claude Code / 代理会话。
> [!TIP]
> 检索在本地针对 SQLite 文件运行 —— **确定性、离线和每个答案几百个令牌** 而不是将整个解决方案提供给模型。 协议详情请参见 [`specs/codemap-mcp.md`](specs/codemap-mcp.md)。
---
## 🔎 在真实示例上查看它
存储库提供了一个自包含的示例解决方案 — [`samples/SampleShop`](samples/SampleShop) — 一个现实的 **8 项目** 布局,混合了 **API 测试和 UI 测试**,因此映射有许多连接的节点并练习了 API 客户端映射(真正的 `HttpClient` 客户端)和页面对象映射(真正的 Selenium `IWebDriver` 页面):
```text
┌─▶ Api.Catalog ──┐
Tests.Api ────────────┼─▶ Api.Cart ──┤
Tests.E2E ──┬─────────┴─▶ Api.Identity ──┼─▶ Core (ApiClientBase : HttpClient)
└─▶ Ui.Pages ─────────────────┘ (PageBase : IWebDriver)
Tests.Ui ────▶ Ui.Pages ──────────────────▶ Core
```
| 项目 | 角色 |
|---|---|
| **Core** | 每个客户端/页面继承的基本类型(最高入度 → 最大节点) |
| **Api.Catalog / Api.Cart / Api.Identity** | `HttpClient` 基於的 API 客户端 |
| **Ui.Pages** | Selenium 页面对象(登录 / 结算 / 产品) |
| **Tests.Api / Tests.Ui / Tests.E2E** | Reqnroll 套件,其步骤驱动客户端和页面 |
两个提交的输出,由工具从该解决方案生成 — 映射显示 **8 个项目和 11 个依赖关系**:
📊 **[示例报告](https://htmlpreview.github.io/?https://github.com/Karzone/TestAtlas/blob/main/docs/sample-report.html)** — 功能、场景、步骤绑定、类类型、API 端点
<br>
🕸️ **[示例依赖关系图](https://htmlpreview.github.io/?https://github.com/Karzone/TestAtlas/blob/main/docs/sample-map.html)** — 八个项目及其之间的边
> [!TIP]
> GitHub 提供 `.html` 作为原始源代码,因此上面的链接通过 `htmlpreview.github.io` 进行路由。 您也可以下载 [`docs/sample-report.html`](docs/sample-report.html) / [`docs/sample-map.html`](docs/sample-map.html) 并在本地打开它们。
<details>
<summary>自己重现它们</summary>
<br>
```bash
testatlas index samples/SampleShop/SampleShop.sln --output sampleshop.db
testatlas report sampleshop.db --html docs/sample-report.html
testatlas map sampleshop.db --html docs/sample-map.html
```
</details>
---
## 🔄 保持映射新鲜
TestAtlas 的答案是确定性的 — 但仅限于映射的新鲜程度。 重新索引时源码更改,以便查询永远不会返回 *确定性过时* 的答案。
### 检查映射是否过时
```bash
python scripts/check-map-age.py [path/to/map.db] # 默认为 ./codemap.db,然后是 ./atlas.db
```
它读取映射的 `generated_utc` + `solution_path`,然后扫描 **作者** 源代码(`*.cs` / `*.feature`)自上次修改以来是否发生更改 — 忽略生成的代码
(`*.feature.cs`、`*.g.cs`、`*.designer.cs`)、`bin`/`obj` 和任何嵌套解决方案。
| 退出代码 | 含义 |
|:--:|---|
| `0` | **新鲜** — 自构建映射以来没有源代码更改 |
| `1` | **过时** — 重新运行 `testatlas index` |
| `2` | **无映射** — 无内容可检查 |
*(Python 3,仅限标准库 — 在 Windows、macOS、Linux 上运行。)*
### 在每次拉取后自动警告(git 钩子)
版本控制的 `post-merge` 钩子会在每次合并 / `git pull` 后运行检查 — 它只打印,从不阻止:
```bash
git config core.hooksPath scripts/hooks # 启用一次,每个克隆
```
钩子自动检测 `codemap.db` / `atlas.db` 在存储库根目录,或者显式指向 `export TESTATLAS_DB=/path/to/your/map.db`。
### 如何在 CI 中重新索引(任何提供商)
三个步骤:**安装工具 → 运行 `testatlas index` → 发布 `.db` 构件。**
<details>
<summary><strong>GitHub Actions</strong> — <code>.github/workflows/testatlas.yml</code></summary>
<br>
```yaml
name: TestAtlas map
on:
push:
branches: [ main ]
jobs:
map:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- run: dotnet tool install --global TestAtlas.Cli
- run: testatlas index YourSolution.sln --output codemap.db
- uses: actions/upload-artifact@v4
with:
name: testatlas-map
path: codemap.db```
</details>
## 🚀 Roadmap
- [x] **索引器 CLI** — C# 索引器 + 文档化的版本化 SQLite 模式 *(v0.1)*
- [x] **HTML 可视化** — 自包含的报告 + 从数据库生成的项目映射
- [x] **MCP 服务器** — `testatlas-mcp` 通过 stdio JSON-RPC 将映射公开给 AI 代理
- [ ] **第二语言索引器** — 相同的模式,契约测试
---
## 📄 许可
[MIT](LICENSE) © 2026 Karthik Kalaiyarasu