sosalejandro/testreg
GitHub: sosalejandro/testreg
面向 Go+TypeScript 单体仓库的全栈依赖追踪与测试覆盖率注册表,以业务功能为粒度精准揭示测试缺口。
Stars: 0 | Forks: 0
# testreg
**面向多语言代码库的全栈依赖追踪与测试覆盖率注册表。**
testreg 维护着一个 YAML 注册表,将业务功能映射到它们在 Go、TypeScript、Playwright、Jest、Vitest 和 Maestro 中的测试。它解析 Go 和 TypeScript 的 AST 以构建全栈依赖图——从 React 路由到 SQL 查询——并将它们与测试覆盖率进行交叉比对,以准确揭示哪里存在缺口。
## 快速示例
使用一条命令追踪登录功能的完整依赖链:
```
$ testreg trace auth.login
Feature: Login (auth.login)
Priority: critical
API Surfaces:
POST /api/v1/auth/login
route:/login apps/web/src/router.tsx:142
└─ LoginPage apps/web/src/pages/auth/LoginPage.tsx:13
└─ useAuth apps/web/src/hooks/useAuth.ts:19
└─ authApi.login apps/web/src/services/api/auth.ts:46
└─ POST /api/v1/auth/login src/infrastructure/http/handlers/auth_handler.go:576
└─ AuthHandler.Login src/infrastructure/http/handlers/auth_handler.go:249
└─ authService.Login src/application/services/auth_service.go:172
├─ JWTGenerator.GenerateTokenPair src/infrastructure/auth/jwt_generator.go:70
│ ├─ JWTGenerator.GenerateAccessToken src/infrastructure/auth/jwt_generator.go:97
│ └─ JWTGenerator.GenerateRefreshToken src/infrastructure/auth/jwt_generator.go:123
├─ authRepository.StoreRefreshToken src/domain/repositories/auth_repository.go:329
├─ repositories.HashToken src/domain/repositories/auth_repository.go:90
└─ sql:GetUserByEmail src/domain/repositories/queries/user.sql:21
Confidence: 100% | Nodes: 11 | Depth: 7
```
*输出结果来自 [nutrition-project-v2](https://github.com/sosalejandro/nutrition-project-v2) —— 一个包含 184 个功能、1103 个测试文件和 2,122 个源文件的全栈 Go + React 单体仓库。*
无需手动连线。testreg 会解析 Go AST,解析 Wire 依赖注入绑定,将 SQLC 生成的方法映射到其 SQL 源文件,并针对前端运行 TypeScript 扫描器——这一切都是自动完成的。
## 功能特性
- **全栈依赖追踪** -- 从 React 路由到 Go 处理程序再到 SQL 查询,均从源代码解析
- **Go 后端零配置** -- 基于 AST 的自动发现可在没有注解的情况下处理约 95% 的调用边
- **以功能为中心的覆盖率** -- 将业务功能(不仅是文件)映射到它们在所有平台上的测试
- **统一健康度审计** -- 结合依赖追踪、测试覆盖率和缺口严重性的各功能健康度评分
- **故障分诊** -- 将错误症状与依赖图进行匹配,以精确定位首先需要检查的文件
- **图表导出** -- 输出 Graphviz DOT、Mermaid 和 JSON 格式以供可视化
- **多框架支持** -- 支持 Go、Vitest、Playwright、Jest 和 Maestro 测试运行器
- **Wire、Fx 和 SQLC 集成** -- 自动解析 DI 绑定和生成的查询映射
- **TypeScript AST 扫描** -- 解析 React Router、TanStack Query 钩子和 API 服务文件
- **API 契约提取** -- `testreg contract` 显示从 GraphQL schema 到 SQL 查询的完整输入/输出类型
- **自动脚手架** -- `testreg init --discover` 从实际路由(Chi、Echo、stdlib)创建功能
- **Sprint 规划** -- 按优先级加权的缺口评分,以决定接下来测试什么
- **AI 就绪输出** -- `testreg gaps --format prompt` 生成结构化输出,供 AI 编程代理使用
## 安装
```
go install github.com/sosalejandro/testreg@latest
```
或从源码构建:
```
git clone https://github.com/sosalejandro/testreg.git
cd testreg
go build -o testreg .
```
如需前端图表支持,请安装 TypeScript 依赖:
```
cd testreg && npm install
```
**系统要求:** Go 1.25+,Node.js 22+(用于 TypeScript 扫描器,可选)
## 快速入门
```
# 1. 使用模板 YAML 文件初始化 registry
testreg init
# 2. 或者从你的 router 自动发现功能 (Chi, Echo, stdlib)
testreg init --discover
# 3. 在你的测试文件中添加 @testreg annotations(参见下方的 Annotations)
# 4. 扫描项目以将测试映射到功能
testreg scan
# 5. 查看覆盖率仪表板
testreg status
# 6. 追踪某个功能的完整依赖链
testreg trace auth.login
# 7. 对所有功能运行健康审计
testreg audit
```
## 命令
testreg 有 16 个按工作流阶段组织的命令。每个命令在 [`docs/commands/`](docs/commands/) 中都有详细的参考文档。
### 了解你的代码库
| 命令 | 描述 | 参考 |
|---------|-------------|-----------|
| [`trace`](docs/commands/trace.md) | 追踪某个功能的全栈依赖图 | [trace.md](docs/commands/trace.md) |
| [`graph`](docs/commands/graph.md) | 将依赖图导出为 DOT、Mermaid 或 JSON 格式 | [graph.md](docs/commands/graph.md) |
| [`contract`](docs/commands/contract.md) | 显示各层的 API 契约和函数签名 | [contract.md](docs/commands/contract.md) |
### 衡量覆盖率
| 命令 | 描述 | 参考 |
|---------|-------------|-----------|
| [`scan`](docs/commands/scan.md) | 发现测试文件并将它们映射到功能 | [scan.md](docs/commands/scan.md) |
| [`status`](docs/commands/status.md) | 按领域和平台划分的覆盖率仪表板 | [status.md](docs/commands/status.md) |
| [`check`](docs/commands/check.md) | 单个功能的详细覆盖率 | [check.md](docs/commands/check.md) |
| [`report`](docs/commands/report.md) | 生成 Markdown 或 JSON 覆盖率报告 | [report.md](docs/commands/report.md) |
| [`audit`](docs/commands/audit.md) | 包含缺口分析的统一健康度报告 | [audit.md](docs/commands/audit.md) |
### 规划与修复
| 命令 | 描述 | 参考 |
|---------|-------------|-----------|
| [`sprint`](docs/commands/sprint.md) | 用于 Sprint 规划的按优先级排序的缺口列表 | [sprint.md](docs/commands/sprint.md) |
| [`gaps`](docs/commands/gaps.md) | 面向人类或 AI 代理的可执行缺口提取 | [gaps.md](docs/commands/gaps.md) |
| [`diagnose`](docs/commands/diagnose.md) | 将错误症状匹配到依赖图层级 | [diagnose.md](docs/commands/diagnose.md) |
### 运行与追踪
| 命令 | 描述 | 参考 |
|---------|-------------|-----------|
| [`run`](docs/commands/run.md) | 执行某个功能或优先级别的测试 | [run.md](docs/commands/run.md) |
| [`update`](docs/commands/update.md) | 摄入测试结果(Playwright、go test、Maestro) | [update.md](docs/commands/update.md) |
| [`diff`](docs/commands/diff.md) | 比较跨 Sprint 的健康度快照 | [diff.md](docs/commands/diff.md) |
| [`metrics`](docs/commands/metrics.md) | 质量信号:执行慢、不稳定、竞态条件 | [metrics.md](docs/commands/metrics.md) |
### 设置
| 命令 | 描述 | 参考 |
|---------|-------------|-----------|
| [`init`](docs/commands/init.md) | 使用模板或自动发现引导注册表 | [init.md](docs/commands/init.md) |
### 全局标志
```
--registry-dir Path to registry YAML files (default: docs/testing/registry)
--project-root Project root directory (auto-detected from git root)
--metrics Show performance metrics after command execution
```
## 工作流
### 首次使用(项目引导)
```
# 1. 根据你的实际路由脚手架生成功能(无需 annotations)
testreg init --discover
# 2. 扫描以映射现有测试文件
testreg scan
# 3. 查看你当前的进度
testreg audit --summary
# 4. 检查 _unmapped.yaml 以寻找需要 @testreg annotations 的测试
# 5. 添加 annotations,重新扫描,建立基线
testreg scan && testreg audit
```
### 编码前(理解阶段)
```
# 查看你即将处理的功能的完整调用图
testreg trace
# 查看哪些部分有测试覆盖,哪些没有
testreg audit
# 为设计文档或 PR 生成可视化图表
testreg graph --format mermaid
```
### 编码后(验证阶段)
```
# 使用你的新 annotations 更新 registry
testreg scan
# 运行针对你所更改功能的全部测试
testreg run
# 检查你的更改是否提升了健康评分
testreg audit
```
### 当测试失败时
```
# 诊断 —— 将错误与已知模式进行匹配
testreg diagnose --symptom "401 Unauthorized"
# 输出: Layer: backend-auth → Check: auth_service.go, 然后 user_repo.go
# 追踪 —— 查看完整的依赖链以获取上下文
testreg trace
```
### Sprint 规划
```
# 1. 保存基线
testreg diff --save-snapshot sprint-3
# 2. 查看按优先级排序的差距列表
testreg sprint --priority critical,high -n 20
# 3. 为 AI subagents 提取可操作的差距
testreg gaps --priority critical --format prompt > /tmp/gaps.md
# 4. 在 sprint 之后,衡量改进情况
testreg diff
```
## testreg 最适用的场景(以及不适用的场景)
testreg 不是一个通用工具。它对你的代码库结构有特定的假设。
### testreg 对你的 Go 后端有何假设
| 假设 | testreg 的期望 | 否则会发生什么 |
|------------|---------------------|----------------------|
| **包命名** | 名为 `handler*/`、`service*/`、`repository*/`、`persistence*/` 的目录 | 函数被归类为 `service`(默认)。健康度评分权重可能会出错,但图表仍然可以构建。 |
| **结构体字段注入** | 依赖项存储为结构体字段:`type Handler struct { service AuthService }` | 通过构造函数参数、闭包或全局变量的调用对扫描器是**不可见的**。边缘会丢失。 |
| **分层架构** | Handler → Service → Repository → Query 调用流程 | 健康度评分权重(handler 30%、service 30%、repository 25%、query 15%)基于这种分层。扁平化架构会导致分数出现偏差。 |
### 依赖注入支持
| DI 方案 | 支持级别 | 详情 |
|-------------|--------------|---------|
| **Google Wire** | 完全支持 | 解析 `wire.Bind()` 和提供者函数,以解析接口到具体类型的映射 |
| **Uber Fx / Dig** | 完全支持 | 解析 `fx.Provide()`、`fx.Options()`、`fx.Invoke()` 和 `dig.Provide()`,以解析提供者返回类型 |
| **手动连线(结构体字段)** | 完全支持 | 只要依赖项是结构体字段,AST 扫描器就能解析它们 |
| **手动连线(构造函数参数)** | 部分支持 | 构造函数调用可见,但通过参数的调用不会被追踪 |
| **无 DI(闭包/全局变量)** | 无 | 捕获的变量和全局单例无法通过 AST 追踪 |
### 路由器支持
| 路由器 | 支持级别 | 详情 |
|--------|--------------|---------|
| **Chi** | 自动检测 | `r.Get()`、`r.Post()`、`r.Route()`、`r.Group()`、`r.With()` |
| **Echo** | 自动检测 | `e.GET()`、`e.POST()`、`e.Group()`、`e.Any()` |
| **stdlib `net/http`** | 自动检测 | `mux.HandleFunc()`、`mux.Handle()`,Go 1.22+ 模式路由 |
| **Gin, Fiber, gorilla/mux** | 通过 `@api` 注解 | 这些框架不提供自动检测 |
### 数据访问与前端支持
| 工具/框架 | 支持级别 |
|----------------|--------------|
| **SQLC** | 完全支持 -- 将生成的 Go 方法映射到 SQL 源文件 |
| **React Router + TanStack Query** | 通过 TypeScript AST 完全自动发现 |
| **Raw SQL / ORM** | 不支持图表追踪 |
| **Vue, Svelte, Angular** | 仅通过注解进行覆盖率追踪(无调用图) |
### `@api` 应急方案
对于 testreg 无法自动检测的任何模式:
```
// @api POST /api/v1/auth/login
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) { ... }
```
适用于**任何** Go HTTP 框架。优先于自动检测的路由。
## 核心概念
### 功能 ID
业务功能的主要标识符:`.[.]`
```
auth.login -- User login flow
recipes.create -- Create a new recipe
plans.nutritionist.list -- List plans (nutritionist view)
```
### 节点类型
对节点在架构中的角色进行分类:
| 类型 | 描述 | 颜色 | 审计权重 |
|------|-------------|-------|-------------|
| `handler` | HTTP/gRPC 处理程序 | 青色 | 30% |
| `service` | 业务逻辑 | 绿色 | 30% |
| `repository` | 数据访问 | 黄色 | 25% |
| `query` | SQL 查询 (SQLC) | 品红色 | 15% |
| `component` | React 页面/组件 | 青色 | -- |
| `hook` | React 钩子 | 绿色 | -- |
| `endpoint` | API 边界 (URL) | 白色 | -- |
| `external` | 外部服务 | 红色 | -- |
### 健康度评分
按各层测试覆盖率加权的平均值:
```
Health = (handler_coverage × 0.30) + (service_coverage × 0.30)
+ (repository_coverage × 0.25) + (query_coverage × 0.15)
```
| 范围 | 含义 |
|-------|---------|
| 80-100% | 测试充分,可安全交付 |
| 50-79% | 存在缺口,交付前需复查 |
| 0-49% | 缺口重大,优先进行测试 |
### 缺口严重度
| 严重度 | 标准 |
|----------|----------|
| CRITICAL | 没有单元测试的 Handler 或 Service |
| HIGH | 没有集成测试的 Repository |
| MEDIUM | 没有测试的 SQL 查询 |
| LOW | 其他未经测试的节点 |
### 测试状态
| 符号 | 含义 |
|--------|---------|
| `✓` | 一个测试文件直接覆盖了该函数所在的文件 |
| `◐` | 相关目录中存在测试 |
| `✘` | 未找到测试文件 |
## 注解
### `@testreg` -- 将测试映射到功能
```
// @testreg auth.login
func TestLoginSuccess(t *testing.T) { ... }
```
```
// @testreg auth.login
test('should login with valid credentials', async () => { ... });
```
```
# @testreg auth.login #real
def test_login_success(client):
...
```
```
# @testreg auth.login
appId: com.example.app
```
**多个功能:** `@testreg auth.login,auth.session`
**标志:** `@testreg auth.login #mocked #slow`
| 标志 | 含义 |
|------|---------|
| `#real` | 真实的集成测试(非模拟) |
| `#mocked` | 测试使用了模拟对象 |
| `#wip` | 进行中的工作 |
| `#flaky` | 已知的不稳定测试 |
### `@api` -- 将处理程序映射到 HTTP 端点
```
// @api POST /api/v1/auth/login
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) { ... }
```
### `@calls` -- 声明隐藏的调用边
```
// @calls notification_service.SendEmail
func (s *OrderService) PlaceOrder(...) { ... }
```
## 配置
testreg 从项目根目录的 `.testreg.yaml` 读取其配置。所有字段均为可选——当文件缺失或字段被省略时,将应用合理的默认值。
### 完整示例
```
graph:
backend_root: src
router_file: src/infrastructure/http/router.go
wire_file: src/infrastructure/config/wire.go
fx_dir: src/pkg/application/common
sqlc_config: sqlc.yaml
frontend_roots:
- apps/web/src
ignore_packages: [vendor, testutil]
ignore_functions: ["String", "Error", "MarshalJSON"]
cache_dir: .testreg-cache
max_depth: 10
type_checking: false
concurrency: 4
graphql:
schema_dirs:
- src/training/pkg/schema
layer_rules:
handler: ["controladores", "controllers", "api"]
repository: ["dao", "store", "repositorios"]
service: ["usecase", "interactor"]
query: ["queries"]
```
### 字段参考
| 字段 | 类型 | 默认值 | 描述 |
|-------|------|---------|-------------|
| `backend_root` | string | `"src"` | 存放 Go 源文件的根目录。testreg 递归遍历此目录以发现所有用于 AST 解析的 `.go` 文件。将其设置为你的 Go 包的起始位置(例如,如果包位于仓库根目录则为 `"."`,单体仓库则为 `"src"`)。| `router_file` | string | `""` | 包含 HTTP 路由注册的 Go 文件(或目录)的路径。用于自动发现 Chi、Echo 和 stdlib 路由器的路由。如果省略,则仅使用 `@api` 注解来映射端点。可以是单个文件(`router.go`)或目录(扫描其中的所有 `.go` 文件)。 |
| `wire_file` | string | `""` | Google Wire DI 文件的路径。testreg 解析 `wire.Bind()` 调用和提供者函数,以解析接口到具体类型的映射。这使得调用图能够跟踪通过接口的调用(例如,`h.service.Login()`,其中 `service` 是通过 Wire 绑定到具体类型的接口)。 |
| `fx_dir` | string | `""` | 包含 Uber Fx 或 Dig 提供者模块的目录。testreg 扫描 `fx.Provide()`、`fx.Options()`、`fx.Invoke()` 和 `dig.Provide()` 调用以解析 DI 绑定。与 `wire_file` 互斥——请使用你的项目实际使用的 DI 框架。 |
| `sqlc_config` | string | `""` | `sqlc.yaml` 的路径。testreg 解析此文件以将 SQLC 生成的 Go 方法映射到其原始的 `.sql` 源文件和行号。如果没有此项,SQL 查询节点将不会出现在图表中。 |
| `frontend_roots` | []string | `[]` | 要扫描 TypeScript/React 源代码的目录。每个目录都会被扫描以查找 React Router 路由定义、组件导入、hook 使用情况以及 API 服务调用。需要设置 `TESTREG_TS_SCANNER` 环境变量并在 testreg 目录中执行 `npm install`。 |
| `ignore_packages` | []string | `[]` | 在 AST 扫描期间要跳过的 Go 包目录名称。适用于排除 `vendor/`、`testutil/`、`mocks/` 或其他会给调用图增加噪音的目录。 |
| `ignore_functions` | []string | `[]` | 要从图表中排除的函数名 glob 模式。常见的排除项:`"String"`、`"Error"`、`"MarshalJSON"`——这些实用方法会使追踪变得杂乱且无助于提供洞察。 |
| `cache_dir` | string | `".testreg-cache"` | 用于缓存已解析 AST 数据、快照和指标历史记录的目录。 |
| `max_depth` | int | `10` | 最大调用图遍历深度。防止在深度嵌套的调用链中出现无限递归。可以通过各命令的 `--depth` 选项覆盖。 |
| `type_checking` | bool | `false` | **实验性功能——不推荐使用。** 启用 `go/types` 以进行精确的跨包类型解析。请参阅“性能”部分中的警告。 |
| `concurrency` | int | `4` | 用于 AST 扫描的最大并行 goroutine 数量。在具有多核的机器上增加此值可加快图表构建速度。 |
| `graphql.schema_dirs` | []string | `[]` | 包含 `.graphqls` schema 文件的目录。被 `testreg contract` 用于将 GraphQL mutation/query 定义显示为契约链中的第一层。 |
| `layer_rules.handler` | []string | `[]` | 被归类为 `handler` 的额外目录名模式。扩展了内置默认值(`handler`、`resolver`)。示例:`["controladores", "controllers", "api"]` |
| `layer_rules.service` | []string | `[]` | 被归类为 `service` 的额外目录名模式。扩展了内置默认值(`service`)。示例:`["usecase", "interactor"]` |
| `layer_rules.repository` | []string | `[]` | 被归类为 `repository` 的额外目录名模式。扩展了内置默认值(`repository`、`persistence`)。示例:`["dao", "store", "repositorios"]` |
| `layer_rules.query` | []string | `[]` | 被归类为 `query` 的额外目录名模式。扩展了内置默认值(`generated`)。示例:`["queries"]` |
### 按项目类型划分的最小配置
**仅 Go 后端(Chi 路由器,Wire DI,SQLC):**
```
graph:
backend_root: src
router_file: src/infrastructure/http/router.go
wire_file: src/infrastructure/config/wire.go
sqlc_config: sqlc.yaml
```
**仅 Go 后端(Echo 路由器,Uber Fx):**
```
graph:
backend_root: .
router_file: internal/server/routes.go
fx_dir: internal/providers
```
**仅 Go 后端(无 DI 框架,无 SQLC):**
```
graph:
backend_root: .
```
在这种情况下,请在处理程序上使用 `@api` 注解,并在任何通过接口的调用上使用 `@calls` 注解。
**全栈 Go + React:**
```
graph:
backend_root: src
router_file: src/infrastructure/http/router.go
wire_file: src/infrastructure/config/wire.go
sqlc_config: sqlc.yaml
frontend_roots:
- apps/web/src
```
**完全没有配置文件:**
testreg 仍然可以工作——它默认从 `src/` 开始扫描,仅使用 `@api` 注解进行路由,并依赖目录命名进行层分类。
### 环境变量
| 变量 | 用途 |
|----------|---------|
| `TESTREG_TS_SCANNER` | TypeScript 扫描器脚本的路径。设置此项可启用前端图表扫描。如果没有此项,则仅追踪 Go 后端。 |
## 层级识别
testreg 将调用图中的每个函数分类到架构层(`handler`、`service`、`repository`、`query`、`external`)中。此分类驱动健康度评分权重和缺口严重性。了解它的工作原理有助于你组织项目结构,以便 testreg 产生准确的结果。
### 层级是如何分配的
**后端** —— 分类基于包含 Go 文件的**目录名**:
| 目录包含 | 分配的层 | 示例 |
|-------------------|---------------|---------|
| `handler` 或 `resolver` | `handler` | `handlers/`、`http/handler/`、`resolvers/` |
| `repository` 或 `persistence` | `repository` | `repositories/`、`persistence/`、`repo/` |
| `service` | `service` | `services/`、`application/services/` |
| `generated` | `query` | `generated/`(SQLC 输出) |
| *(其他任何)* | `service`(默认) | `utils/`、`pkg/`、`internal/` |
匹配是不区分大小写的,并使用 `strings.Contains`,因此 `my_handlers/` 和 `UserHandler/` 都会匹配 `handler`。嵌套路径同样适用——`src/infrastructure/http/handlers/auth_handler.go` 会匹配,因为路径中包含 `handler`。
**SQLC 查询** —— 由 SQLC 生成的方法被分类为 `query` 并链接到其 `.sql` 源文件。这是通过解析 `sqlc_config` 实现的,而非目录命名。
**外部调用** —— 对 Go 标准库包(`http.`、`fmt.`、`json.`、`context.`、`strings.` 等)的调用被分类为 `external`,并从健康度评分中排除。
**前端** —— TypeScript 扫描器会发出明确的类别标签:
| 类型 | 匹配内容 |
|------|----------------|
| `component` | 从路由定义导入的 React 页面/组件文件 |
| `hook` | React 钩子(`use*` 函数) |
| `endpoint` | API 路由路径(API 服务文件中的 URL 字符串) |
### 这对你的项目意味着什么
**如果你的目录遵循约定**,一切都会自动运行:
```
src/
├── infrastructure/
│ └── http/
│ └── handlers/ ← classified as "handler"
├── application/
│ └── services/ ← classified as "service"
├── domain/
│ └── repositories/ ← classified as "repository"
└── generated/ ← classified as "query" (SQLC)
```
**如果你的目录不匹配**,testreg 仍然可以构建图表——但一切都会默认为 `service`。这意味着:
- 健康度评分出现偏差(所有权重都归入 service 层)
- 缺口严重性可能有误(一个 handler 的缺口被报告为 service 级别)
- 追踪树仍然可以正常工作(边缘基于 AST,而非命名)
**要修复错误分类的层**,你有三个选择:
1. 在 `.testreg.yaml` 中**添加 `layer_rules`**,以告知 testreg 你的命名约定(推荐)
2. **重命名目录**,使其包含 `handler`、`service`、`repository` 或 `persistence`
3. **接受默认设置** —— 图表和追踪依然准确,仅健康度评分和缺口严重性会受影响
**示例 —— 非英语代码库:**
```
graph:
layer_rules:
handler: ["controladores", "controllers"]
repository: ["repositorios", "dao", "store"]
service: ["servicios", "usecase"]
```
自定义规则会在内置默认值**之前**被检查。它们是对默认值的扩展,因此内置模式(`handler`、`service`、`repository`、`persistence`、`generated`)仍可与你的自定义模式一同使用。
### 能正常工作的常见目录结构
```
# Clean architecture
src/handlers/ → handler
src/services/ → service
src/repositories/ → repository
# Hexagonal architecture
src/infrastructure/http/handlers/ → handler
src/application/services/ → service
src/domain/repositories/ → repository
# 领域驱动(使用约定)
src/auth/handler/ → handler
src/auth/service/ → service
src/auth/persistence/ → repository
# 扁平结构(一切默认为 service)
src/auth/ → service (default)
src/meals/ → service (default)
```
### 没有 `layer_rules` 就无法正常工作的结构
```
# 无命名约定 —— 一切都变成 "service"
src/auth/auth.go → service (should be handler? service? unknown)
src/auth/auth_db.go → service (should be repository)
# 非英文命名 —— 默认设置无法识别这些内容
src/controladores/ → service (should be handler)
src/repositorios/ → service (should be repository)
```
**使用 `layer_rules` 修复:**
```
graph:
layer_rules:
handler: ["controladores"]
repository: ["repositorios"]
```
对于没有任何命名约定的扁平结构(`src/auth/auth.go`),请使用 `@api` 注解标识处理程序,并接受健康度评分将是近似值。
## 注册表 YAML 格式
每个域作为独立的 YAML 文件存储在注册表目录中:
```
domain: auth
description: Authentication and authorization features
features:
- id: auth.login
name: User Login
description: Email/password authentication with JWT tokens
roles: [patient, nutritionist, admin]
priority: critical
surfaces:
web:
route: /login
component: LoginPage
mobile:
screen: LoginScreen
api:
- method: POST
path: /api/v1/auth/login
coverage:
unit:
backend:
status: covered
files: [src/services/auth_service_test.go]
mocked: true
web:
status: missing
integration:
backend:
status: covered
files: [src/handlers/auth_e2e_test.go]
mocked: false
e2e:
web:
status: covered
files: [e2e/auth.spec.ts]
last_run: "2026-03-30"
pass_rate: 1.0
```
**覆盖率状态值:** `covered`、`partial`、`missing`、`failing`
**优先级级别:** `critical`、`high`、`medium`、`low`
## testreg 的工作原理
testreg 结合了三种类型的分析:手动维护的 YAML 定义、源代码的静态分析(Go AST、TypeScript AST),以及基于启发式的文件存在性匹配。
```
Registry YAML ──┐
Go AST scanner ──┼──▶ Unified Graph ──▶ Trace ──▶ Audit
TS AST scanner ──┘ │ │
Nodes + Edges Test status (heuristic)
(deterministic) Health score (weighted avg)
Gap severity (rule-based)
```
### 图表扫描器阶段
1. **预解析** -- 解析 `sqlc.yaml` 以将生成的 Go 方法映射到 SQL 源文件
2. **路由发现** -- 解析路由文件 + `@api` 注解以提取 HTTP 路由
3. **函数发现** -- 遍历所有 `.go` 文件,创建节点,构建结构体字段类型映射,解析 Wire/Fx 绑定
4. **调用图提取** -- 遍历函数体,通过字段查找和 DI 绑定解析调用,添加边缘
TypeScript 扫描器作为 Node.js 子进程运行,使用 `ts.createSourceFile` 提取 React Router 路由、组件→hook→API 调用链。
### 测试覆盖率检测
5 策略文件匹配启发式方法:
1. **精确约定匹配** -- `auth_handler.go` → `auth_handler_test.go` → `tested`
2. **相同目录匹配** -- 相同目录中的测试文件 → `partial`
3. **基本名匹配** -- 任何位置共享相同基本名 → `partial`
4. **包名匹配** -- 共享目录段 → `partial`
5. **无匹配** → `untested`
### 局限性
- 测试状态基于文件存在性,而非通过/失败
- `partial` 在健康度评分中计为 `tested`(可能会使其虚高)
- 缺口严重性由架构层固定,而非基于风险
- 性能缺口检测(`func Benchmark*`、`t.Parallel()`)是文本模式匹配
- 默认扫描器使用 `go/ast` 而没有 `go/types` —— 无法解析超出 Wire/Fx 绑定范围的接口实现
- 从 `go test -json` 推断功能 ID 属于基于启发式的最佳猜测
## CI 集成
### 注解强制执行
```
- name: Check test annotations
run: |
testreg scan
testreg report
GAPS=$(sed -n '/## Unannotated Test Files/,/^##/p' docs/testing/COVERAGE.md | grep -c "^- " || true)
if [ "$GAPS" -gt 0 ]; then
echo "::error::$GAPS test files missing @testreg annotations"
exit 1
fi
```
### PR 覆盖率评论
```
- name: Post coverage summary
run: |
testreg scan
testreg status > /tmp/coverage.txt
gh pr comment ${{ github.event.pull_request.number }} --body "$(cat /tmp/coverage.txt)"
```
### Sprint 进度追踪
```
- name: Save health snapshot
if: github.ref == 'refs/heads/main'
run: |
testreg diff --save-snapshot "ci-$(date +%Y%m%d)"
git add .testreg-cache/snapshots/
git diff --cached --quiet || git commit -m "chore: update health snapshot"
```
## 常见误区
| 误区 | 正确做法 |
|---------|-----------------|
| `grep -r "@testreg auth" tests/` | `testreg scan && testreg status --domain auth` |
| `find tests/ -name "*_test.go" \| wc -l` | `testreg status` |
| 80 行的 python 覆盖率报告脚本 | `testreg scan && testreg report` |
| `jq` 流水线按优先级过滤审计 | `testreg audit --priority critical` |
| Python 脚本按优先级评分排序 | `testreg sprint` |
| 手动进行前后对比的 JSON 比较 | `testreg diff --save-snapshot` / `testreg diff` |
| Python 脚本为子代理提取缺口 | `testreg gaps --format actionable` |
| 每次都运行 `scan && audit` | `testreg audit --rescan` |
## 性能
在真实的单体生产仓库(nutrition-project-v2:184 个功能,1103 个测试文件,全栈 Go + React + TypeScript)上测量。
| 命令 | 执行时间 | 功能说明 |
|---------|-----------|-------------|
| `testreg scan` | **0.5s** | 在 8 个并行扫描器中发现 1103 个测试文件 |
| `testreg trace auth.login` | **0.7s** | 构建全栈调用图,追踪 16 个节点 |
| `testreg audit auth.login` | **0.7s** | 对单个功能执行追踪 + 注解 + 健康度评分 |
| `testreg audit --all` | **13s** | 审计所有 184 个功能(图表只构建一次) |
| `testreg sprintn 10` | **10s** | 按优先级加权缺口评分对所有 184 个功能进行排序 |
| 场景 | 峰值 RSS |
|----------|----------|
| 小型项目(41 个功能,42 个测试文件) | **17 MB** |
| 大型单体仓库(184 个功能,1103 个测试文件) | **153 MB** |
```
Binary: ~12 MB (static, single file)
Source: 15,207 lines (production code)
Tests: 12,694 lines (371 tests)
Dependencies: 3 direct (cobra, yaml.v3, x/tools)
```
关键优化:`ExecuteAll` 构建图表一次,然后根据共享图表追踪每个功能。优化前:184 个功能需要 1 分 52 秒。优化后:**14 秒**(7.9 倍加速)。
## 架构
```
cmd/ Cobra command definitions (CLI entry points)
internal/
domain/ Core types: Feature, Registry, Graph, Node, Edge, Audit
ports/ Interface definitions (GraphBuilder, RegistryStore, TestScanner)
app/ Use cases orchestrating domain logic
adapters/ Implementations:
go_ast_scanner Go AST parsing (go/ast, go/parser) for call graph construction
frontend_scanner Invokes ts-scanner.ts for TypeScript AST parsing
route_parser Chi/Echo/stdlib router file parsing for route discovery
wire_resolver Wire dependency injection binding resolution
sqlc_mapper SQLC config parsing to map generated methods to SQL sources
annotation_parser @testreg and @api annotation extraction
yaml_store Registry persistence (YAML read/write)
*_scanner Test file discovery (Go, Vitest, Playwright, Jest, Maestro)
*_reporter Output rendering (terminal, markdown, JSON)
ts-scanner.ts TypeScript AST scanner (ts.createSourceFile)
```
## 支持的框架
### 后端
| 框架 | 发现方法 |
|-----------|-----------------|
| Chi | 路由文件解析(自动) |
| Echo | 路由文件解析(自动) |
| stdlib `net/http` | 路由文件解析(自动) |
| 任何 Go HTTP 框架 | `@api` 注解 |
### 前端
| 框架 | 发现方法 |
|-----------|-----------------|
| React Router | TypeScript AST 扫描(自动) |
| TanStack Query | Hook 调用分析(自动) |
| 任何框架 | `@testreg` 注解(仅覆盖率追踪) |
### 依赖注入
| 工具 | 集成 |
|------|------------|
| Wire | 从 `wire.go` 自动解析绑定 |
| Uber Fx / Dig | 自动解析提供者 |
| SQLC | 自动进行方法到 SQL 的映射 |
### 测试运行器
| 运行器 | 文件模式 | 平台 |
|--------|-------------|----------|
| Go test | `*_test.go` | 后端 |
| Vitest | `*.test.ts` | Web |
| Playwright | `*.spec.ts` | Web E2E |
| Jest | `__tests__/**` | 移动端 |
| Maestro | `*.yaml`(在 e2e 目录中) | 移动端 E2E |
| pytest | `test_*.py`、`*_test.py` | 后端 |
## 贡献
欢迎贡献。在提交 Pull Request 之前,请开启一个 Issue 讨论重大变更。
```
go test ./... # Run tests
go build -o testreg . # Build
go install . # Install locally
```
## 许可证
[Apache 2.0](LICENSE)
版权所有 2026 Alejandro Sosa
标签:Anchore, API契约, AST解析, DNS解析, EVTX分析, Go, Jest, Maestro, Playwright, React, Ruby工具, SQL, Syscalls, TypeScript, Vitest, 业务特性审计, 云安全监控, 代码分析, 依赖图, 全栈依赖追踪, 凭证管理, 单体仓库, 安全插件, 开源项目, 数据管道, 日志审计, 测试覆盖率, 特征检测, 端到端测试, 系统审计, 软件工程, 静态分析