ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

构建多语言测试分析知识库:test-analysis-extensions 技能的设计与实战指南

构建多语言测试分析知识库:test-analysis-extensions 技能的设计与实战指南 构建多语言测试分析知识库test-analysis-extensions 技能的设计与实战指南【免费下载链接】skillsRepository for skills to assist AI coding agents with .NET and C#项目地址: https://gitcode.com/GitHub_Trending/skills17/skills导读test-analysis-extensions是 dotnet-test 插件中一个特殊的数据服务型技能它本身不执行分析而是为assertion-quality、test-anti-patterns、test-gap-analysis、test-smell-detection、test-tagging五个多语言测试分析技能提供按语言拆分的框架速查表。本文将从该技能的定义、11 个扩展文件的组织方式、Capability tags 门控机制、调用协议到各语言框架的检测细节完整讲解这套语言无关分析引擎 语言相关参考数据的解耦设计并给出基于仓库源码的落地实践。读完本文你将掌握如何在 .NET、Python、TypeScript、Java、Go 等 10 语言生态中统一检测测试断言、睡眠模式、跳过注解、Mystery Guest 耦合等测试味道并理解auto-edit/report-only/convention-based三种标签能力分级的取舍逻辑。一、技能定位为什么需要一个只提供数据的技能1.1 从 SKILL.md 元数据看定位在 SKILL.md 的 frontmatter 中该技能有三条关键声明user-invocable: false——用户不能直接调用disable-model-invocation: true——模型也不能自行触发description——明确指出它是被test-quality-auditoragent 与多语言分析技能内部调用的框架特定查找表提供者。也就是说它是一个纯粹的infrastructure skill正确的调用方式是先调用它拿到扩展文件清单再读取与目标代码库语言、测试框架匹配的那一个文件。这与 dotnet-test 插件中其他分析技能如 assertion-quality、test-smell-detection形成了明确的调用方—数据方关系。1.2 为什么要把参考数据从分析逻辑中剥离从源码结构看整个体系的设计意图是语言无关的分析引擎 语言相关的参考数据分析技能assertion-quality、test-anti-patterns 等只描述如何分类、如何报告的通用方法论具体某个框架的断言 API 长什么样、跳过注解怎么写、sleep 模式有哪些全部下沉到扩展文件中。以 assertion-quality/SKILL.md 的说明为例它明确要求在分类断言之前 MUST 读取相关的扩展文件因为不同框架的断言 API 差异巨大。test-smell-detection/SKILL.md 同样要求对不熟悉的框架 API调用test-analysis-extensions并读取对应扩展文件。这样做的收益有三点新增一种语言不需要改动分析引擎只要新增一个extensions/xxx.md所有分析技能自动获得该语言的支持避免模型凭空猜测框架 API没有参考数据时模型可能把 pytest 的裸assert误判为缺少框架断言 API把 Go 的if ... t.Errorf误判为异味——扩展文件正是为了校准这类判断报告口径一致每个扩展文件都按相同的类别组织见下文分析技能可以做到语言中立。二、扩展文件清单11 种语言生态一网打尽SKILL.md 的Available Extension Files一节列出了当前仓库 extensions 目录下全部 11 个文件。下表是完整清单及对应语言/框架文件语言/框架覆盖要点extensions/dotnet.md.NETC#/F#/VB— MSTest、xUnit、NUnit、TUnit测试标记、断言 API、sleep 模式、跳过注解、Mystery Guest、集成标记、setup/teardown、标签支持extensions/python.mdPython — pytest、unittest同上 pytest fixtures/markers、unittest TestCaseextensions/typescript.mdTypeScript/JavaScript — Jest、Vitest、Mocha、Jasmine、node:test同上 async/await 陷阱extensions/java.mdJava — JUnit 4、JUnit 5Jupiter、TestNG同上 Tag/Category/ groupsextensions/go.mdGo —testing包、testify同上 table-driven 惯用法、build tagsextensions/ruby.mdRuby — RSpec、Minitest同上 RSpec metadata、Minitest tagsextensions/rust.mdRust — 内置#[test]、cargo test同上 #[ignore]、#[should_panic]、feature flagsextensions/swift.mdSwift — XCTest、Swift Testing同上 Test、Tag、Suiteextensions/kotlin.mdKotlin — JUnit 5、Kotest、MockK同上 Tag、Kotest tagsextensions/powershell.mdPowerShell — Pester v5同上 -Tag、Skipextensions/cpp.mdC — GoogleTest、Catch2、doctest同上 [tags]、*过滤器注意 dotnet.md 同时覆盖 MSTest、xUnit、NUnit、TUnit 四个框架并在标题注明Reference data for analyzing .NET test code是唯一以 .NET 为主场的文件也是本仓库.NET 技能集合最核心的扩展。三、Capability tags让分析技能安全地门控行为每个扩展文件头部都声明一张Capability tags表描述该语言/框架对各项检测能力的支持强度。SKILL.md 列出了统一的能力维度Test discovery——如何定位测试文件和测试方法Assertion detection——框架级与语言级断言语法的识别能力Sleep/delay patterns——同步与异步等待的识别Skip / ignore——如何识别被跳过/忽略的测试Setup / teardown——fixture 与生命周期钩子Mystery guest indicators——常见的文件/数据库/网络/环境耦合模式Integration markers——标记集成/E2E 测试的约定Tag support供test-tagging技能使用——三选一auto-edit——语言存在规范的属性/标记技能可以安全地写入report-only——没有规范语法只能生成审计报告而不做修改convention-based——标签仅通过命名/注释约定存在。各语言的 Tag support 分级直接决定了test-tagging技能的行为模式这是最容易产生差异的部分值得单独列出语言Tag support 分级规范语法.NETauto-edit[TestCategory]、[Trait]、[Category]、[Property]Pythonauto-editpytestpytest.mark.tagunittest 无规范语法Javaauto-editJUnit 5Tag、JUnit 4Category、TestNGgroupsKotlinauto-editJUnit 5Tag、KotesttagsSwiftauto-editSwift TestingTest(.tags(...))/Suite(.tags(...))XCTest 为 report-onlyRubyauto-editRSpec metadata、Minitest tag经 gemPowerShellauto-editDescribe/Context/It的-Tag参数Cauto-edit部分Catch2[tag]、doctesttest_suiteGoogleTest 视为 convention-basedTypeScript/JSreport-only无规范属性依赖 describe 分组/命名前缀约定Goreport-only无规范属性build tags 粒度太粗Rustreport-only / convention-based无规范属性模块分组/命名前缀3.1 分级背后的原因从 typescript.md 可以看到JS/TS 生态的默认模式是report-only因为 Jest/Vitest/Mocha 都没有一等公民的 tag 属性它提供了 describe 前缀分组如describe(positive | OrderService, ...)、测试名前缀it([boundary] handles zero quantity, ...)、Vitest options 对象、自定义 reporter 四种替代策略并且明确只有当项目已经遵循其中一种约定时通过采样现有测试检测才切换到 auto-edit 模式。go.md 同样标注report-onlyGo 没有 per-test tag 属性build tags 只能按文件粒度切分且很粗因此建议使用 subtest 名称编码t.Run([positive] valid input returns ok, ...)或函数名前缀TestNegative_InvalidInput_Returns400并在项目已有约定时再切换到 auto-edit。这种分级的意义在于标签写入是有副作用的操作。对没有规范语法的语言强行自动打标签要么产生无效代码要么污染测试仓库。test-tagging技能据此在安全自动编辑与仅出报告之间做出保守选择。四、Usage标准调用协议SKILL.md 定义了四步调用流程这也是所有上游分析技能的约定用法检测目标代码库的主语言与测试框架在执行分析之前读取匹配的扩展文件若存在多个测试框架例如一个项目同时混用 Jest 和 Mocha则读取所有相关扩展文件每个扩展文件都按相同类别组织使分析技能可以保持语言中立。assertion-quality 的调用方式印证了这一协议识别目标代码库的语言与测试框架调用test-analysis-extensions技能并读取匹配的扩展文件如 .NET 用extensions/dotnet.mdpytest 用extensions/python.mdJest/Vitest 用extensions/typescript.mdGo 用extensions/go.md。扩展文件列出了你将在第 3 步分类的框架级断言 API。五、扩展文件内部结构以 dotnet.md 为例的深度解析每个扩展文件遵循相同的章节骨架。我们以本仓库最核心的 dotnet.md 为例逐节拆解其内容与实战价值。5.1 测试文件识别框架测试类标记测试方法标记MSTest[TestClass][TestMethod]、[DataTestMethod]xUnit无基于约定[Fact]、[Theory]NUnit[TestFixture][Test]、[TestCase]、[TestCaseSource]TUnit无基于约定[Test]5.2 断言 API 对照表类别MSTestxUnitNUnitTUnit相等Assert.AreEqualAssert.EqualAssert.That(x, Is.EqualTo(y))await Assert.That(x).IsEqualTo(y)布尔Assert.IsTrue/IsFalseAssert.True/FalseAssert.That(x, Is.True)await Assert.That(x).IsTrue()空Assert.IsNull/IsNotNullAssert.Null/NotNullAssert.That(x, Is.Null)await Assert.That(x).IsNull()异常Assert.ThrowsT()/ThrowsExactlyT()Assert.ThrowsT()Assert.That(() ..., Throws.TypeOfT())await Assert.That(() ...).ThrowsT()集合CollectionAssert.ContainsAssert.ContainsAssert.That(col, Has.Member(x))await Assert.That(col).Contains(x)字符串StringAssert.ContainsAssert.Contains(str, sub)Assert.That(str, Does.Contain(sub))await Assert.That(str).Contains(sub)类型Assert.IsInstanceOfTypeAssert.IsAssignableFromAssert.That(x, Is.InstanceOfT())await Assert.That(x).IsAssignableToT()不确定Assert.Inconclusive()[Fact(Skip)]Assert.Inconclusive()Skip.Test(reason)失败Assert.Fail()Assert.Fail().NET 10Assert.Fail()Assert.Fail()TUnit 特别提醒TUnit 的断言是异步的、必须await——遗漏await会导致断言永不执行、测试静默通过。多个断言可通过.And/.Or链式组合或用Assert.Multiple()分组。第三方断言库dotnet.md 亦列出Should*Shouldly、.Should()FluentAssertions / AwesomeAssertions、Verify()VerifyTUnit 自带TUnit.Assertions.Should。5.3 Sleep/Delay 模式与跳过注解sleep 模式三类Thread.Sleep(2000)、await Task.Delay(1000)、SpinWait.SpinUntil(() condition, timeout)。跳过注解对照框架注解带原因MSTest[Ignore][Ignore(reason)]xUnit[Fact(Skip reason)]原因必填NUnit[Ignore(reason)]原因必填TUnit[Skip(reason)]原因必填可作用于类/程序集级别动态跳过用Skip.Test(reason)条件编译#if false/#if NEVER无原因5.4 异常断言的惯用替代方案当测试用try/catch验证异常时应优先使用框架原生形式// MSTest精确类型 var ex Assert.ThrowsExactlyInvalidOperationException(() sut.Do()); Assert.AreEqual(expected message, ex.Message); // xUnit var ex Assert.ThrowsInvalidOperationException(() sut.Do()); // NUnit var ex Assert.ThrowsInvalidOperationException(() sut.Do()); // TUnit await Assert.That(() sut.Do()).ThrowsInvalidOperationException();5.5 Mystery Guest常见 .NET 耦合模式指示器应查找的内容文件系统File.ReadAllText、File.Exists、Directory.GetFiles、带硬编码路径的Path.Combine数据库SqlConnection、DbContext未使用内存 provider、SqlCommand网络未覆盖HttpMessageHandler的HttpClient、WebRequest、TcpClient环境Environment.GetEnvironmentVariable、Environment.CurrentDirectory可接受MemoryStream、StringReader、内存数据库 provider、自定义DelegatingHandler5.6 集成测试标记以下特征应识别为集成测试相应降低味道严重度类名包含Integration、E2E、EndToEnd或Acceptance[TestCategory(Integration)]MSTest[Trait(Category, Integration)]xUnit[Category(Integration)]NUnit、TUnit项目名以.IntegrationTests或.E2ETests结尾。5.7 Setup/Teardown 对照框架SetupTeardownMSTest[TestInitialize]或构造函数[TestCleanup]或IDisposable.DisposexUnit构造函数IDisposable.Dispose/IAsyncDisposable.DisposeAsyncNUnit[SetUp][TearDown]TUnit[Before(Test)]或构造函数[After(Test)]或IDisposable.DisposeMSTest类级[ClassInitialize][ClassCleanup]NUnit类级[OneTimeSetUp][OneTimeTearDown]xUnit类级IClassFixtureTfixture 的DisposeTUnit类级[Before(Class)][After(Class)]5.8 Tag/Trait 属性供 test-tagging 使用框架现有属性示例MSTest[TestCategory(...)][TestCategory(positive)]xUnit[Trait(Category, ...)][Trait(Category, positive)]NUnit[Category(...)][Category(positive)]TUnit[Category(...)]或[Property(Category, ...)][Category(positive)]放置规则将 trait 属性放在现有测试属性的紧邻上方或下方一行同一测试允许多个 trait。5.9 .NET 语言特有校准注意事项这是扩展文件最有价值的防误判部分MSTest 4 的 sealed 测试类是为了锁定类布局的有意设计不是味道xUnit 每个测试一个实例构造函数中初始化的字段会在测试间重置——General Fixture过度宽泛 setup检测仍应标记字段使用率 50%的情况TUnit 的 await 要求本身是无断言味道的高发来源任何缺少await的 TUnit 断言行都应标记为关键反模式数据驱动测试[DataRow]、[Theory]/[InlineData]、[TestCase]、[Arguments]不是重复测试应视为合并形式。六、多语言纵深关键框架的检测要点每个扩展文件都包含大量语言特有校准说明它们是分析准确性的关键。以下为各语言最值得注意的要点。6.1 Pythonpytest / unittest裸assert是 pytest 的规范断言经断言重写产生丰富失败 diff不要把裸assert标记为缺少框架 API味道异步测试中协程调用缺失await会产生RuntimeWarning且测试实际无断言——标记为关键反模式快照测试syrupy、pytest-snapshot与基于假设的属性测试hypothesisgiven都算合法断言pytest.mark.parametrize是参数化测试不是重复仅被一个测试使用的 fixture 不是 General Fixture 味道——pytest fixture 是按需付费的pytest 打标时需在 pyproject.toml /pytest.ini中注册 markers避免PytestUnknownMarkWarning扩展文件给出了完整的[tool.pytest.ini_options] markers [...]配置示例。6.2 TypeScript/JavaScriptJest / Vitest / Mocha / Jasmine / node:test未 await 的 Promise 断言是致命的expect(promise).resolves.toBe(...)不写await就静默通过可用 linter 规则typescript-eslint/no-floating-promises兜底expect(mock).toHaveBeenCalled()是合法断言不要判为无断言Mocha 风格的done回调若未调用done()会静默通过提交到源码的.onlyfit/fdescribe是关键味道——会静默禁用整个套件Jest 27 已移除fail()检测if (cond) fail(msg)模式应建议改用throw new Error(msg)或显式失败断言describe.each/test.each是参数化测试不算重复。6.3 JavaJUnit 4 / JUnit 5 / TestNGTestNG 陷阱Assert.assertEquals(actual, expected)与 JUnit 的参数顺序相反错序会产出反向失败消息JUnit 4Test(expected ...)丢失精确异常位置且接受子类建议迁移到assertThrowsSpringBootTest会启动整个应用几乎总是集成测试AssertJ 链式断言概念上是一个断言不要按链长计数Mockitoverify(...)是状态/副作用断言不要判为无断言Maven Surefire 可在 pom.xml 的configurationgroupspositive,critical-path/groups/configuration中注册组过滤。6.4 Gotesting 包 / testify裸if ... { t.Errorf(...) }是 Go 的规范断言形式不要标记为未使用框架 APItable-driven 测试中的for循环不要标记为 Conditional Test Logicrequire.*调用t.FailNow()立即停止测试assert.*记录失败后继续——前置条件应优先用require测试内的t.Setenv后再t.Parallel()在新版 Go 会失败goroutine 泄漏建议用goleak.VerifyNone(t)带// Output:块的 Example 函数是测试输出块即断言fuzz 测试没有f.Add(...)种子可能只在-fuzz下运行——标记为覆盖缺口构建标签//go:build integration通过go test -tagsintegration运行是 Go 门控集成测试的惯用手段。6.5 KotlinJUnit 5 / Kotest / MockK协程测试必须在边界使用runTest/runBlockingrunTest使用虚拟时间测试时间相关代码应优先于runBlockingMockKverify { }不带exactly N只检查至少调用一次断言精确行为应设置计数Kotest 的forAll(...)是数据驱动不算重复OptIn(ExperimentalCoroutinesApi::class)是常见实践不是味道AndroidMediumTest/LargeTest视作集成标记Compose UI 测试createComposeRule是 UI 集成测试Gradle 中可用 build.gradle.kts 的useJUnitPlatform { includeTags(positive); excludeTags(slow) }做标签过滤。6.6 Rust内置 #[test] / cargo test#[should_panic]不带expected ...时任何 panic 都通过——过于宽泛是味道异步测试缺少#[tokio::test]会静默不运行——标记任何缺失运行时属性的async fn测试#[ignore]不带原因应标记为低严重度 Ignored Testthread::sleep是 Sleepy Test异步场景优先tokio::time::pause()doc tests 是真实测试cargo test会运行#[cfg(test)]模块 #![deny(warnings)]有时会构建失败提示但不标记为味道变更static mut或全局Mutex状态的测试需要#[serial]serial_test crate否则并行cargo test下会不稳定。6.7 SwiftXCTest / Swift TestingSwift Testing 的#expect失败后继续、try #require中止测试——前置条件应使用try #require异步测试必须await缺失会产生警告和静默跳过XCTestExpectationwait(for:timeout:)是 XCTest 惯用的异步协调模式不是 sleep 味道XCTWaiter、await fulfillment(of:timeout:)Xcode 14同样可接受Swift Testing 默认每个测试新实例init中初始化的字段会在测试间重置.xctestplan测试计划可按 tag/配置过滤是 per-test 打标之外的结构性替代方案。6.8 RubyRSpec / Minitest谓词匹配器be_empty、be_valid自动从对象的?方法派生是合法断言change匹配器验证副作用不要判为缺少断言共享示例it_behaves_like ...与共享上下文不是重复测试是合并形式pending与skip不同pending运行测试并预期失败skip不运行FactoryBotcreate会写数据库、build不会——只做非持久化断言时用create会徒增测试时间RSpec 过滤可用rspec --tag positive、rspec --tag ~slowRails 7.1 提供test_taggedhelper。6.9 PowerShellPester v5Pester v5 的发现/运行分离Describe/Context块在 discovery 阶段执行It块中使用的变量必须用BeforeAll初始化——在Describe作用域定义变量再在It中使用会得到$nullTestDrive:是 Pester 自动创建的每个测试独立的临时目录不是 Mystery GuestShould -Invokev5/Assert-MockCalledv4是状态/副作用断言Mock不加ParameterFilter会拦截作用域内任何函数——过度宽泛标记为味道-ForEach/-TestCases是参数化测试不算重复Pester v6预览变更了部分 API若项目面向 v6 需复核断言形式。6.10 CGoogleTest / Catch2 / doctest / Boost.TestGoogleTestEXPECT_*失败后继续、ASSERT_*中止Catch2/doctest 对应CHECK*/REQUIRE*Boost.Test 对应BOOST_CHECK*/BOOST_REQUIRE*——长测试的前置条件用中止型DISABLED_前缀会静默禁用测试且需--gtest_also_run_disabled_tests才能重新启用——提交在源码中的DISABLED_测试标记为 Ignored TestCatch2 的SECTION会为每个组合重入父TEST_CASE体相当于每次 section 的全新 setup——强大惯用法且不是重复测试GoogleMockEXPECT_CALL(...)是状态/副作用断言SUCCEED()/INFO(...)不是断言只有SUCCEED()的测试是无断言的过滤语法示例Catch2./tests [positive] ~[slow]、doctest./tests -tspositive、GoogleTest./tests --gtest_filterPositive*、Boost.Test./tests --run_testpositive。七、对技能作者的约束与最佳实践SKILL.md 的Notes for skill authors一节对维护者提出了三条明确约束这也是把扩展文件当作数据而非指导的核心原则把扩展文件当作数据而不是需要逐字遵循的指导。它们告诉技能如何在每种语言中检测事物而不是对发现结果应该如何思考。也就是说扩展文件负责模式匹配如何识别Thread.Sleep语义判断这是否是味道、严重度多高仍由调用方的分析技能负责语言检测不确定时优先读取多个扩展文件而不是猜测。这与 Usage 第 3 步呼应混用 Jest 与 Mocha 的项目应同时读 typescript.md 的相关框架节而不是只读一个用户明确指定了尚无扩展文件的框架时回退到最接近的一个例如 Pest → python.md/pytest 语义并在报告中注明差距。这个回退 报告差距的机制保证了体系的可扩展性——新增框架不需要阻塞分析流程。八、在仓库中继续深入如果你想继续研究这套体系以下文件是最佳入口扩展文件清单与调用协议plugins/dotnet-test/skills/test-analysis-extensions/SKILL.md全部 11 个语言参考文件plugins/dotnet-test/skills/test-analysis-extensions/extensions/五个主要调用方技能plugins/dotnet-test/skills/assertion-quality/SKILL.md断言质量强制先读扩展文件再分类plugins/dotnet-test/skills/test-anti-patterns/SKILL.md反模式检测plugins/dotnet-test/skills/test-gap-analysis/SKILL.md测试缺口分析plugins/dotnet-test/skills/test-smell-detection/SKILL.md测试味道检测plugins/dotnet-test/skills/test-tagging/SKILL.md测试打标按 Tag support 分级决定 auto-edit 还是 report-only。这些技能配套的评估夹具与 eval 配置位于 tests/dotnet-test 目录如 assertion-quality、test-smell-detection 等可以用 eng/run-skill-evals.sh 结合 skill-validator 工具链进行回归验证。结语test-analysis-extensions用 11 个结构高度一致的 Markdown 文件把跨语言测试分析这个原本高度依赖模型常识的任务变成了可查表、可校准、可扩展的确定性流程。它的设计精髓在于三点数据与逻辑分离分析引擎语言中立、能力分级门控auto-edit / report-only / convention-based 保护标签写入安全、防误判校准各语言特有的不要标记清单。无论你是想为自家多语言测试仓库接入统一的质量分析还是想理解 AI Agent 技能体系中参考数据层的架构模式这套实现都提供了完整的参考样板。【免费下载链接】skillsRepository for skills to assist AI coding agents with .NET and C#项目地址: https://gitcode.com/GitHub_Trending/skills17/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表