name: 测试结构分析 description: 直接分析测试代码结构以提供覆盖率分析
测试结构分析技能
该技能提供直接从测试文件中分析测试代码结构的能力,无需运行测试。它检查测试文件和源文件,以识别已测试和未测试的内容。
何时使用此技能
在以下情况下使用此技能:
- 无需运行测试,分析测试代码组织
- 识别未测试的文件和函数
- 了解端到端/集成测试覆盖范围
- 通过检查测试结构发现覆盖率差距
- 生成全面的测试结构报告
- 快速分析(秒级,而非分钟级)
前提条件
必需工具
- Python 3.8+ 用于测试结构分析
- Go 工具链 用于目标 Go 项目
安装
# 确保已安装 Python 3.8+
python3 --version
# 目标项目的 Go 工具链
go version
工作原理
注意:此技能目前仅支持 Go 项目。
步骤 1:发现测试和源文件
分析器基于 Go 约定发现测试和源文件:
测试文件:
- 以
_test.go结尾的文件 - 端到端/集成测试通过以下方式识别:
- 文件命名模式:
*e2e*_test.go,*integration*_test.go - 目录位置:
test/e2e/,test/integration/,e2e/,integration/ - 内容标记:Ginkgo 标记如
[Serial],[Disruptive],g.Describe(,g.It(
- 文件命名模式:
源文件:
- 以
.go结尾的文件(排除测试文件) - 可选排除供应商、生成代码等
步骤 2:解析测试文件
对每个测试文件,提取:
-
测试函数/方法:
- 函数名称
- 行号范围
- 测试框架(Go testing, Ginkgo)
- 测试类型(单元、集成、端到端)
-
测试目标(测试什么):
- 对源文件的导入和引用
- 函数调用和实例化
- 从测试名称推断
-
测试元数据:
- 测试描述/文档
- 测试标签/标记
- 辅助函数
Go 示例:
// 文件:pkg/handler_test.go
package handler_test
import (
"testing"
"myapp/pkg/handler"
)
func TestHandleRequest(t *testing.T) { // ← 测试函数
h := handler.New() // ← 目标:handler.New
result := h.HandleRequest("test") // ← 目标:handler.HandleRequest
// ...
}
提取结果:
{
"test_file": "pkg/handler_test.go",
"source_file": "pkg/handler.go",
"tests": [
{
"name": "TestHandleRequest",
"lines": [6, 10],
"targets": ["handler.New", "handler.HandleRequest"],
"type": "unit"
}
]
}
步骤 3:解析源文件
对每个源文件,提取:
-
函数/方法:
- 函数名称
- 行号范围
- 可见性(公开/私有/导出)
- 参数和返回类型
- 复杂度指标
-
类/结构体:
- 类型定义
- 方法
- 字段
Go 示例:
// 文件:pkg/handler.go
package handler
type Handler struct {
config Config
}
func New() *Handler { // ← 函数:New
return &Handler{}
}
func (h *Handler) HandleRequest(req string) (string, error) { // ← 函数:HandleRequest
if req == "" {
return "", errors.New("empty request")
}
return process(req), nil
}
提取结果:
{
"source_file": "pkg/handler.go",
"functions": [
{
"name": "New",
"lines": [8, 10],
"visibility": "exported",
"complexity": 1
},
{
"name": "HandleRequest",
"lines": [12, 20],
"visibility": "exported",
"complexity": 3,
"receiver": "Handler"
}
]
}
步骤 4:映射测试到源代码
创建测试与源代码之间的映射:
-
直接映射(测试文件 → 源文件):
handler_test.go→handler.go
-
函数级映射(测试 → 函数):
TestHandleRequest测试HandleRequest
-
基于导入的映射:
- 分析测试文件中的导入以识别测试模块
映射结果:
{
"pkg/handler.go": {
"test_file": "pkg/handler_test.go",
"functions": {
"New": {
"tested": true,
"tests": ["TestHandleRequest"],
"test_count": 1
},
"HandleRequest": {
"tested": true,
"tests": ["TestHandleRequest"],
"test_count": 1
}
},
"overall_tested_functions": 2,
"overall_untested_functions": 0,
"function_test_coverage": 100.0
}
}
步骤 5:识别覆盖率差距
识别未测试的内容:
-
未测试的源文件:
- 没有对应测试文件的源文件
- 优先级:基于文件重要性(导出函数)
-
未测试的函数:
- 在任何测试中未引用的函数
- 优先级:导出/公开函数 > 私有函数
-
部分测试的文件:
- 有测试文件但某些函数缺少测试的文件
差距分类:
{
"gaps": {
"untested_files": [
{
"file": "pkg/config.go",
"functions": 5,
"exported_functions": 3,
"priority": "high",
"reason": "未找到对应测试文件"
}
],
"untested_functions": [
{
"file": "pkg/handler.go",
"function": "process",
"visibility": "private",
"priority": "low",
"reason": "在任何测试中未引用"
}
]
},
"summary": {
"total_source_files": 45,
"files_with_tests": 30,
"files_without_tests": 15,
"total_functions": 234,
"tested_functions": 189,
"untested_functions": 45,
"function_coverage_percentage": 80.8
}
}
步骤 6:生成报告
重要: Claude Code 在运行时基于分析器的结构化输出生成所有三种报告格式。分析器脚本返回结构化数据(作为 JSON 到标准输出或通过 Python 数据结构),Claude Code 负责生成所有报告文件。
分析器生成包含完整分析结果的结构化数据。Claude Code 读取此数据并生成三种报告格式:
1. JSON 报告(test-structure-report.json)
生成者: Claude Code 在运行时基于分析器输出
机器可读格式,包含完整分析数据。结构见步骤 5。
如何生成:
- 从分析器读取结构化数据(作为 JSON 返回标准输出)
- 写入 JSON 文件,使用
indent=2提高可读性
2. 文本摘要(test-structure-summary.txt)
生成者: Claude Code 在运行时基于分析器输出
终端友好摘要显示:
- 总体统计(有/无测试的文件,函数覆盖率)
- 高优先级差距
- 建议
格式结构:
============================================================
测试结构分析
============================================================
文件:{文件名}
语言:{语言}
分析日期:{时间戳}
============================================================
覆盖率摘要
============================================================
总源文件: {数量}
有测试的文件: {数量} ({百分比}%)
无测试的文件: {数量} ({百分比}%)
总函数: {数量}
已测试函数: {数量} ({百分比}%)
未测试函数: {数量} ({百分比}%)
============================================================
高优先级差距
============================================================
未测试文件:
1. {文件路径} - {原因} ({函数数量} 个函数,{导出数量} 个导出)
...
未测试函数:
1. {文件路径}::{函数名} - {原因} (可见性:{可见性})
...
============================================================
建议
============================================================
当前覆盖率:{当前}%
目标覆盖率:{目标}%
首先解决高优先级差距,以最大化
测试覆盖率并确保生产就绪性。
3. HTML 报告(test-structure-report.html)
生成者: Claude Code 在运行时基于分析器输出
交互式 HTML 报告,包含:
必需部分:
- 头部 包含项目信息、语言和生成时间戳
- 摘要仪表板 带有分数卡显示:
- 总源文件和有/无测试的文件
- 函数覆盖率百分比
- 高优先级差距计数
- 未测试文件表 包含列:
- 文件路径
- 函数计数
- 导出函数计数
- 优先级(高/中/低)
- 未测试函数表 包含列:
- 文件路径
- 函数名称
- 可见性(导出/私有)
- 复杂度分数
- 优先级
- 建议部分 按优先级分组
样式:
- 使用与差距技能相同的 CSS(现代渐变、卡片、表格)
- 优先级徽章:高(红色)、中(橙色)、低(蓝色)
- 使用
html.escape()转义所有内容
实施步骤
在命令中实施此技能时:
步骤 0:在运行时生成分析器脚本
关键: 在运行任何分析之前,从参考实现生成分析器脚本。
# 创建输出目录
mkdir -p .work/test-coverage/analyze/
# 根据以下规范生成分析器脚本
# Claude Code 将基于分析器规范部分编写 test_structure_analyzer.py
分析器规范:
生成一个 Python 脚本(test_structure_analyzer.py),用于分析 Go 测试结构而无需运行测试:
输入: 路径或 URL 到 Go 测试文件或目录 输出: 结构化 JSON 数据打印到标准输出,可选文本摘要到标准错误
核心算法:
-
输入处理(处理 URL 和本地路径):
- 检查输入是否以
http://或https://开头 - 如果是 URL:使用
urllib.request.urlopen()获取内容,保存到临时文件 - 如果是本地路径:直接使用
- 分析后:如果创建了临时文件,则清理
- 注意:不支持目录 URL,仅支持单文件 URL
- 检查输入是否以
-
文件发现:
- 测试文件:
*_test.go(排除供应商、生成代码) - 端到端测试:
test/e2e/、test/integration/中的文件,或包含[Serial]、[Disruptive]标记的文件 - 源文件:
*.go(排除*_test.go、供应商)
- 测试文件:
-
测试解析(基于正则表达式):
- Ginkgo:
(?:g\.|o\.)?It\(\s*["']([^"']+)["']→ 提取测试名称、行号 - 标准 Go:
func (Test\w+)\(t \*testing\.T\)→ 提取测试函数名称 - 提取目标(调用的函数):在测试体内正则匹配
\w+\([^)]*\)
- Ginkgo:
-
源文件分析:
- 解析函数定义:
func (\w+)\(或func \(\w+ \*?\w+\) (\w+)\( - 跟踪导出与未导出(首字母大写 vs 小写)
- 解析函数定义:
-
测试到源映射:
- 约定:
handler_test.go→handler.go - 函数级:匹配测试名称到源函数名称(例如,
TestHandleRequest→HandleRequest) - 导入分析:解析测试文件中的
import语句
- 约定:
-
单文件模式(当输入是文件而非目录时):
- 仅分析测试文件结构
- 提取:测试计数、测试名称、导入、行号
- 跳过源文件映射和差距检测
- 输出:仅测试结构分析
-
输出格式(JSON 到标准输出):
{
"language": "go",
"source_dir": "/path/to/src",
"test_only_mode": false,
"summary": {
"total_source_files": 45,
"total_test_files": 32,
"untested_files_count": 8
},
"test_file_details": {
"path": "/path/to/test.go",
"test_count": 15,
"tests": [
{"name": "TestFoo", "line_start": 10, "line_end": 20, "targets": ["Foo", "Bar"]}
],
"imports": ["testing", "github.com/onsi/ginkgo"]
}
}
命令行界面:
python3 .work/test-coverage/analyze/test_structure_analyzer.py <源路径> [--test-structure-only] [--output <目录>]
为什么在运行时生成:
- Claude Code 根据此规范生成分析器
- 无需维护单独的
.py文件 - SKILL.md 是单一来源
- 更简单、更易维护
步骤 1:验证输入
检查源目录是否存在,如果未指定则检测语言。
步骤 2:执行测试结构分析器
# 运行分析器(输出结构化 JSON 到标准输出)
python3 .work/test-coverage/analyze/test_structure_analyzer.py \
<源目录> \
--priority <优先级> \
--output-json
分析器将输出结构化 JSON 到标准输出,包含:
- 测试文件分析
- 源文件分析
- 测试到源映射
- 覆盖率差距
- 摘要统计
步骤 3:在运行时生成所有三种报告格式
重要: Claude Code 基于分析器的结构化输出生成所有三种报告格式。
3.1:捕获和解析分析器输出
import json
import subprocess
# 运行分析器并捕获 JSON 输出
result = subprocess.run(
['python3', '.work/test-coverage/analyze/test_structure_analyzer.py', source_dir, '--output-json'],
capture_output=True,
text=True
)
# 解析结构化数据
analysis_data = json.loads(result.stdout)
3.2:生成 JSON 报告
json_path = '.work/test-coverage/analyze/test-structure-report.json'
with open(json_path, 'w') as f:
json.dump(analysis_data, f, indent=2)
3.3:生成文本摘要报告
遵循步骤 6 中的文本格式规范生成终端友好摘要。
text_path = '.work/test-coverage/analyze/test-structure-summary.txt'
# 根据步骤 6 中的格式生成文本内容
with open(text_path, 'w') as f:
f.write(text_content)
3.4:生成 HTML 报告
遵循步骤 6 中的 HTML 规范生成交互式报告。
html_path = '.work/test-coverage/analyze/test-structure-report.html'
# 根据步骤 6 中的规范生成 HTML 内容
with open(html_path, 'w') as f:
f.write(html_content)
步骤 4:显示结果
向用户显示摘要和报告位置:
测试结构分析完成
已生成报告:
✓ HTML: .work/test-coverage/analyze/test-structure-report.html
✓ JSON: .work/test-coverage/analyze/test-structure-report.json
✓ 文本: .work/test-coverage/analyze/test-structure-summary.txt
⚠️ 强制预完成验证
关键: 在声明此技能完成之前,必须执行以下所有验证检查。未验证被视为执行不完整。
验证清单
按顺序执行这些验证步骤。所有必须通过:
1. 文件存在检查
# 验证所有三个报告存在
test -f .work/test-coverage/analyze/test-structure-report.html && echo "✓ HTML 存在" || echo "✗ HTML 缺失"
test -f .work/test-coverage/analyze/test-structure-report.json && echo "✓ JSON 存在" || echo "✗ JSON 缺失"
test -f .work/test-coverage/analyze/test-structure-summary.txt && echo "✓ 文本存在" || echo "✗ 文本缺失"
要求: 所有三个文件必须存在。如果有缺失,重新生成。
2. 测试案例提取验证
# 验证测试案例已提取
python3 << 'EOF'
import json
try:
with open('.work/test-coverage/analyze/test-structure-report.json', 'r') as f:
data = json.load(f)
test_count = data.get('summary', {}).get('test_cases_count', 0)
if test_count > 0:
print(f"✓ 测试案例已提取:{test_count}")
else:
print("✗ 未找到测试案例 - 验证测试文件是否包含 Ginkgo 测试")
exit(1)
except Exception as e:
print(f"✗ 错误:{e}")
exit(1)
EOF
要求: 必须提取测试案例。零测试案例表示解析问题。
3. HTML 报告结构验证
# 验证 HTML 有必需部分
grep -q "<h2>测试案例" .work/test-coverage/analyze/test-structure-report.html && \
echo "✓ 测试案例部分存在" || \
echo "✗ 缺失:测试案例部分"
grep -q "<h2>覆盖率摘要" .work/test-coverage/analyze/test-structure-report.html && \
echo "✓ 覆盖率摘要部分存在" || \
echo "✗ 缺失:覆盖率摘要部分"
要求: HTML 必须有所有结构部分。
4. JSON 结构验证
# 验证 JSON 有所有必需字段
python3 << 'EOF'
import json
try:
with open('.work/test-coverage/analyze/test-structure-report.json', 'r') as f:
data = json.load(f)
required_fields = [
('summary.language', lambda d: d['summary']['language']),
('summary.test_cases_count', lambda d: d['summary']['test_cases_count']),
('test_cases', lambda d: d['test_cases']),
]
missing = []
for name, getter in required_fields:
try:
getter(data)
print(f"✓ {name}")
except (KeyError, TypeError):
print(f"✗ 缺失:{name}")
missing.append(name)
if not missing:
print("
✓ 所有必需 JSON 字段存在")
else:
print(f"
✗ 不完整:缺失 {len(missing)} 个必需字段")
exit(1)
except Exception as e:
print(f"✗ 错误:{e}")
exit(1)
EOF
要求: 所有必需 JSON 字段必须存在。
验证摘要
在声明此技能完成之前:
- ✓ 所有三个报告文件存在
- ✓ 成功提取测试案例(计数 > 0)
- ✓ HTML 有所有必需部分
- ✓ JSON 包含所有必需字段
如果任何检查失败: 修复问题并重新运行所有验证检查。在通过所有检查之前,不要声明技能完成。
错误处理
常见问题及解决方案
-
无法解析测试/源文件:
- 使用备用基于正则表达式的解析
- 记录无法解析文件的警告
- 继续部分分析
-
未找到测试文件:
- 检查 Go 项目的测试模式是否正确
- 确保测试文件遵循
*_test.go命名约定
-
复杂项目结构:
- 允许通过
--exclude排除某些目录
- 允许通过
示例
示例 1:Go 项目 - 基本分析
# 分析 Go 项目的测试结构
python3 .work/test-coverage/analyze/test_structure_analyzer.py /path/to/go/project
# 输出:
# 语言:go
# 发现 45 个源文件,32 个测试文件
# 函数覆盖率:80.8%(189/234 个函数已测试)
# 高优先级差距:8 个文件无测试
示例 2:带过滤器的 Go 项目
# 仅分析高优先级差距
python3 .work/test-coverage/analyze/test_structure_analyzer.py /path/to/go/project \
--priority high \
--exclude "*/vendor/*" \
--output reports/test-gaps/
示例 3:单测试文件分析
# 分析单测试文件结构
python3 .work/test-coverage/analyze/test_structure_analyzer.py ./test/e2e/networking/infw.go \
--test-structure-only \
--output ./reports/
与 Claude Code 命令集成
此技能用于:
/test-coverage:analyze <源目录>
该命令调用此技能执行无需运行测试的测试结构分析。
另请参阅
- 测试覆盖率插件 README - 用户指南和安装说明