测试结构分析技能Skill TestStructureAnalysis

测试结构分析技能用于直接从测试文件中分析代码结构,识别测试覆盖情况,无需运行测试。支持Go项目,能提取测试函数、映射源代码、发现覆盖率差距,并生成JSON、文本和HTML报告。关键词:测试分析、代码结构、测试覆盖率、Go测试、结构解析、覆盖率报告。

测试 0 次安装 0 次浏览 更新于 3/14/2026

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:解析测试文件

对每个测试文件,提取:

  1. 测试函数/方法:

    • 函数名称
    • 行号范围
    • 测试框架(Go testing, Ginkgo)
    • 测试类型(单元、集成、端到端)
  2. 测试目标(测试什么):

    • 对源文件的导入和引用
    • 函数调用和实例化
    • 从测试名称推断
  3. 测试元数据:

    • 测试描述/文档
    • 测试标签/标记
    • 辅助函数

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:解析源文件

对每个源文件,提取:

  1. 函数/方法:

    • 函数名称
    • 行号范围
    • 可见性(公开/私有/导出)
    • 参数和返回类型
    • 复杂度指标
  2. 类/结构体:

    • 类型定义
    • 方法
    • 字段

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:映射测试到源代码

创建测试与源代码之间的映射:

  1. 直接映射(测试文件 → 源文件):

    • handler_test.gohandler.go
  2. 函数级映射(测试 → 函数):

    • TestHandleRequest 测试 HandleRequest
  3. 基于导入的映射:

    • 分析测试文件中的导入以识别测试模块

映射结果:

{
  "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:识别覆盖率差距

识别未测试的内容:

  1. 未测试的源文件:

    • 没有对应测试文件的源文件
    • 优先级:基于文件重要性(导出函数)
  2. 未测试的函数:

    • 在任何测试中未引用的函数
    • 优先级:导出/公开函数 > 私有函数
  3. 部分测试的文件:

    • 有测试文件但某些函数缺少测试的文件

差距分类:

{
  "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 报告,包含:

必需部分:

  1. 头部 包含项目信息、语言和生成时间戳
  2. 摘要仪表板 带有分数卡显示:
    • 总源文件和有/无测试的文件
    • 函数覆盖率百分比
    • 高优先级差距计数
  3. 未测试文件表 包含列:
    • 文件路径
    • 函数计数
    • 导出函数计数
    • 优先级(高/中/低)
  4. 未测试函数表 包含列:
    • 文件路径
    • 函数名称
    • 可见性(导出/私有)
    • 复杂度分数
    • 优先级
  5. 建议部分 按优先级分组

样式:

  • 使用与差距技能相同的 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 数据打印到标准输出,可选文本摘要到标准错误

核心算法:

  1. 输入处理(处理 URL 和本地路径):

    • 检查输入是否以 http://https:// 开头
    • 如果是 URL:使用 urllib.request.urlopen() 获取内容,保存到临时文件
    • 如果是本地路径:直接使用
    • 分析后:如果创建了临时文件,则清理
    • 注意:不支持目录 URL,仅支持单文件 URL
  2. 文件发现:

    • 测试文件:*_test.go(排除供应商、生成代码)
    • 端到端测试:test/e2e/test/integration/ 中的文件,或包含 [Serial][Disruptive] 标记的文件
    • 源文件:*.go(排除 *_test.go、供应商)
  3. 测试解析(基于正则表达式):

    • Ginkgo:(?:g\.|o\.)?It\(\s*["']([^"']+)["'] → 提取测试名称、行号
    • 标准 Go:func (Test\w+)\(t \*testing\.T\) → 提取测试函数名称
    • 提取目标(调用的函数):在测试体内正则匹配 \w+\([^)]*\)
  4. 源文件分析:

    • 解析函数定义:func (\w+)\(func \(\w+ \*?\w+\) (\w+)\(
    • 跟踪导出与未导出(首字母大写 vs 小写)
  5. 测试到源映射:

    • 约定:handler_test.gohandler.go
    • 函数级:匹配测试名称到源函数名称(例如,TestHandleRequestHandleRequest
    • 导入分析:解析测试文件中的 import 语句
  6. 单文件模式(当输入是文件而非目录时):

    • 仅分析测试文件结构
    • 提取:测试计数、测试名称、导入、行号
    • 跳过源文件映射和差距检测
    • 输出:仅测试结构分析
  7. 输出格式(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 字段必须存在。

验证摘要

在声明此技能完成之前:

  1. ✓ 所有三个报告文件存在
  2. ✓ 成功提取测试案例(计数 > 0)
  3. ✓ HTML 有所有必需部分
  4. ✓ JSON 包含所有必需字段

如果任何检查失败: 修复问题并重新运行所有验证检查。在通过所有检查之前,不要声明技能完成。

错误处理

常见问题及解决方案

  1. 无法解析测试/源文件:

    • 使用备用基于正则表达式的解析
    • 记录无法解析文件的警告
    • 继续部分分析
  2. 未找到测试文件:

    • 检查 Go 项目的测试模式是否正确
    • 确保测试文件遵循 *_test.go 命名约定
  3. 复杂项目结构:

    • 允许通过 --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 <源目录>

该命令调用此技能执行无需运行测试的测试结构分析。

另请参阅