grade-tests
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseGrade Tests
测试评分
Grade a curated list of test methods and produce a compact, PR-comment-friendly
report: one row per test method with a letter grade, a score band, and a
one-line note explaining the grade. The skill does not discover tests on its
own — the caller (typically a PR automation workflow or a human reviewer
holding a specific list) provides the test methods to grade.
Language-specific guidance: Call theskill to discover available extension files, then read the file matching the target codebase's language and framework (e.g.,test-analysis-extensions,extensions/dotnet.md,extensions/python.md,extensions/typescript.md). You MUST read the relevant extension file before scoring assertions or anti-patterns, because assertion APIs and idiomatic patterns differ significantly across frameworks.extensions/go.md
对精选的测试方法列表进行评分,生成紧凑、适合作为PR评论的报告:每个测试方法对应一行,包含字母等级、分数区间和一行说明评分理由的文字。本skill不会自行发现测试——调用方(通常是PR自动化工作流或持有特定列表的人工审核者)需提供待评分的测试方法。
语言特定指南:调用skill以发现可用的扩展文件,然后读取与目标代码库语言和框架匹配的文件(例如test-analysis-extensions、extensions/dotnet.md、extensions/python.md、extensions/typescript.md)。在对断言或反模式评分前,你必须阅读相关扩展文件,因为不同框架的断言API和惯用模式差异显著。extensions/go.md
Why a Per-Test Grade
为何采用逐测试评分
Suite-wide audits (, ,
) produce excellent diagnostic reports, but they are
hard to consume as a short PR comment. Reviewers of a PR mostly want to know:
for the tests this PR adds or changes, are they good? This skill answers
that question with a one-row-per-test verdict that fits in a comment table.
test-anti-patternsassertion-qualitytest-smell-detection全套件审计(、、)会生成出色的诊断报告,但作为简短的PR评论却难以阅读。PR审核者最想知道的是:*本次PR新增或修改的测试质量如何?*本skill通过每行对应一个测试的结论来回答这个问题,结果可直接放入评论表格中。
test-anti-patternsassertion-qualitytest-smell-detectionWhen to Use
适用场景
- A PR automation workflow needs to post a comment grading the tests introduced or modified in a pull request.
- A reviewer has a specific list of tests (a file, a class, a method list, or a diff hunk) and wants a per-test verdict rather than a suite report.
- A maintainer wants to triage which of N tests in a contribution deserve follow-up improvements.
- PR自动化工作流需要发布评论,对拉取请求中引入或修改的测试进行评分。
- 审核者持有特定测试列表(文件、类、方法列表或代码片段),希望获取逐测试结论而非全套件报告。
- 维护者希望筛选出贡献中的N个测试,确定哪些需要后续改进。
When Not to Use
不适用场景
- The caller wants a full suite audit or comparative metrics — use
(pragmatic) or
test-anti-patterns(formal) and let thetest-smell-detectionagent orchestrate.test-quality-auditor - The caller wants to write new tests — use (any language) or
code-testing-generator(MSTest specifically).writing-mstest-tests - The caller wants to measure code coverage or CRAP scores — use
or
coverage-analysis(.NET only).crap-score - The caller wants to fix issues directly in test code — invoke the appropriate editing skill.
- No specific list of tests is provided. Do not try to grade every test in the workspace; ask the caller for an explicit list or scope.
- 调用方需要全套件审计或对比指标——使用(实用型)或
test-anti-patterns(规范型),并让test-smell-detectionAgent进行协调。test-quality-auditor - 调用方想要编写新测试——使用(支持任意语言)或
code-testing-generator(专为MSTest设计)。writing-mstest-tests - 调用方想要衡量代码覆盖率或CRAP分数——使用或
coverage-analysis(仅支持.NET)。crap-score - 调用方想要直接修复测试代码中的问题——调用相应的编辑skill。
- 未提供特定测试列表。请勿尝试对工作区中的所有测试进行评分;请要求调用方提供明确的列表或范围。
Inputs
输入参数
| Input | Required | Description |
|---|---|---|
| Test methods | Yes | A scope to grade. Provide one of: (a) an explicit list of test method names (fully-qualified, e.g. |
| Test bodies / spans | Recommended | The exact source lines for each test method. If omitted, read them from the listed files. |
| Production code | No | The code under test, for judging whether assertions cover the meaningful behaviors. When unavailable, mark relevant findings as "Unverified" rather than guessing. |
| Diff context | No | When grading PR changes, the unified diff for each test method helps focus on what actually changed. |
| 输入项 | 是否必填 | 描述 |
|---|---|---|
| 测试方法 | 是 | 待评分的范围。提供以下其中一项:(a)明确的测试方法名称列表(完全限定,例如 |
| 测试方法体/范围 | 推荐 | 每个测试方法的精确源代码行。若未提供,则从列出的文件中读取。 |
| 生产代码 | 否 | 被测代码,用于判断断言是否覆盖了有意义的行为。若不可用,将相关发现标记为“未验证”,而非猜测。 |
| 代码差异上下文 | 否 | 对PR变更进行评分时,每个测试方法的统一差异有助于聚焦实际变更内容。 |
Step 0: Validate the input
步骤0:验证输入
Before doing anything else, check that the caller provided one of:
- An explicit list of test method names, or
- One or more file paths plus an explicit instruction to grade every test
declared in those files (e.g., "grade every test in "), or
OrderTests.cs - A diff hunk or PR identifier whose changed tests should be graded.
If the request is ambiguous (e.g., "Grade my tests", "Are these tests
any good?" with no scope, "Review the test suite"), do not load
extensions, do not read files, and do not grade anything. Reply with a
short message asking the caller to provide an explicit list / file(s) /
diff, and optionally point them at agent or
skill for full-suite analysis. Stop there.
test-quality-auditortest-anti-patterns在执行任何操作前,检查调用方是否提供了以下其中一项:
- 明确的测试方法名称列表,或
- 一个或多个文件路径,加上明确的指令要求对这些文件中声明的所有测试进行评分(例如“为中的所有测试评分”),或
OrderTests.cs - 代码片段或PR标识符,需对其中修改的测试进行评分。
如果请求模糊不清(例如:“为我的测试评分”、“这些测试好不好?”但未指定范围、“审核测试套件”),请勿加载扩展、读取文件或进行任何评分。回复简短消息,要求调用方提供明确的列表/文件/差异,并可选择性地引导他们使用 Agent或 skill进行全套件分析。操作到此为止。
test-quality-auditortest-anti-patternsWorkflow
工作流程
Step 1: Detect language and load extension
步骤1:检测语言并加载扩展
Identify the target codebase's language and test framework from the file
extensions and the test method markers in the provided list. Call the
skill and read the matching extension file (e.g.,
for MSTest/xUnit/NUnit/TUnit,
for pytest, for Jest/Vitest,
for the standard package). If the input contains tests from
multiple languages, load each relevant extension and grade each test using
its language's conventions.
test-analysis-extensionsextensions/dotnet.mdextensions/python.mdextensions/typescript.mdextensions/go.mdtesting从文件扩展名和提供列表中的测试方法标记,识别目标代码库的语言和测试框架。调用 skill并读取匹配的扩展文件(例如,针对MSTest/xUnit/NUnit/TUnit的,针对pytest的,针对Jest/Vitest的,针对标准包的)。如果输入包含多种语言的测试,请加载每个相关扩展,并使用对应语言的约定对每个测试进行评分。
test-analysis-extensionsextensions/dotnet.mdextensions/python.mdextensions/typescript.mdtestingextensions/go.mdStep 2: Resolve the test bodies
步骤2:解析测试方法体
For each entry in the input list:
- If the test body is provided inline, use it directly.
- Otherwise read the file at the given path and locate the method by its fully-qualified name. Capture the full method body, including attributes / decorators / fixtures and any helper code that the test calls.
- If a method cannot be found, record it as and continue. Never invent a body to grade.
N/A — method not found
针对输入列表中的每个条目:
- 如果测试方法体已内联提供,则直接使用。
- 否则,读取指定路径的文件,并通过完全限定名称定位方法。捕获完整的方法体,包括属性/装饰器/夹具以及测试调用的任何辅助代码。
- 如果无法找到方法,记录为并继续。切勿虚构方法体进行评分。
N/A — 方法未找到
Step 3: Score each test
步骤3:对每个测试评分
Start every test at grade A (score band 90–100), then apply deductions
strictly for observable issues in the captured body. Do not deduct
for hypothetical concerns (e.g., "could have more negative assertions")
unless the production code clearly demands them and the production code is
available.
When production code is unavailable, grade observable issues in the test body
normally, but do not infer missing behaviors or deduct for them. State
once in the summary so the
reader can distinguish test-body findings from claims that require source code.
Production-dependent behavior coverage: Unverified每个测试初始等级为A(分数区间90–100),然后仅针对捕获的方法体中可观察到的问题进行扣分。请勿因假设性问题(例如“本可添加更多负面断言”)扣分,除非生产代码明确需要且生产代码可用。
当生产代码不可用时,正常对测试方法体中可观察到的问题进行评分,但不要推断缺失的行为或因此扣分。在摘要中注明一次,以便读者区分测试方法体的发现与需要源代码支撑的结论。
生产相关行为覆盖率:未验证Three sub-dimensions
三个子维度
Compute three sub-grades (each A–F) that together drive the overall grade.
计算三个子等级(均为A–F),共同决定最终等级。
A. Assertion strength
A. 断言强度
Read the loaded language extension's assertion API list and classify every
assertion in the test body. Score from highest to lowest:
| Sub-grade | Pattern |
|---|---|
| A | At least one meaningful value assertion (equality / structural / exception / state) plus, where appropriate, additional checks (negative, type, collection contents). Mock-call verifications ( |
| B | One clear meaningful assertion that verifies the behavior under test. |
| C | Only trivial assertions (single |
| D | One self-referential / tautological assertion ( |
| F | No assertions at all; all assertions are always-true literals ( |
Exception and error-path tests (, constrained
, , , ,
, , or Go code that verifies an expected non-nil
error) are complete on their own. Give Assertion strength A when the test
checks the exact promised error condition for its stated scope. Do not deduct
for having only that assertion, and do not require an error-message assertion
unless the message is part of the documented contract. A Go happy-path test
that only checks while discarding a meaningful returned value is
still C because it does not verify the successful result.
Assert.ThrowsException<T>pytest.raisesexpect(fn).toThrowassertThrows#[should_panic]Should -ThrowEXPECT_THROWerr == nil读取已加载语言扩展中的断言API列表,对测试方法体中的每个断言进行分类。评分从高到低如下:
| 子等级 | 模式 |
|---|---|
| A | 至少包含一个有意义的值断言(相等/结构/异常/状态),并在适当情况下包含额外检查(负面、类型、集合内容)。模拟调用验证( |
| B | 一个清晰的有意义断言,验证被测行为。 |
| C | 仅包含琐碎断言(单一 |
| D | 一个自引用/同义反复的断言( |
| F | 无任何断言;所有断言均为恒真字面量( |
异常和错误路径测试(、受限的、、、、、,或验证预期非空错误的Go代码)本身是完整的。当测试检查其声明范围内的确切预期错误条件时,断言强度等级为A。请勿因仅包含该断言而扣分,且除非消息是文档化契约的一部分,否则无需要求错误消息断言。仅检查而丢弃有意义返回值的Go正常路径测试仍为C,因为它未验证成功结果。
Assert.ThrowsException<T>pytest.raisesexpect(fn).toThrowassertThrows#[should_panic]Should -ThrowEXPECT_THROWerr == nilB. Structure & focus
B. 结构与聚焦
| Sub-grade | Pattern |
|---|---|
| A | Clear Arrange-Act-Assert (or Given-When-Then) separation. Single behavior under test. Body under ~30 lines. Setup uses framework conventions. |
| B | One mild structural issue (slightly long body, missing blank lines between phases) but intent is clear. |
| C | Multiple behaviors mixed in one test, or AAA phases interleaved enough to slow comprehension. |
| D | Conditional logic in the test ( |
| F | Test exceeds ~60 lines and verifies multiple unrelated behaviors; or shares mutable state with other tests through statics/globals without reset. |
| 子等级 | 模式 |
|---|---|
| A | 清晰的Arrange-Act-Assert(或Given-When-Then)分离。单一被测行为。方法体约30行以内。使用框架约定进行初始化。 |
| B | 存在一个轻微的结构问题(方法体略长、阶段间缺少空行),但意图清晰。 |
| C | 一个测试中混合了多个行为,或AAA阶段交错严重影响理解。 |
| D | 测试中包含条件逻辑( |
| F | 测试超过约60行并验证多个无关行为;或通过静态/全局变量与其他测试共享可变状态且未重置。 |
C. Anti-pattern hygiene
C. 反模式合规性
Scan against the catalog below. The Anti-pattern sub-grade is computed
in two passes and combined deterministically:
- Hard ceiling pass. Every Critical or High finding sets a maximum sub-grade (F, D, or C as labeled). Take the worst ceiling across all matched Critical/High findings — these do not accumulate (a single F finding caps the sub-grade at F regardless of how many other Critical/High findings are present).
- Medium-deduction pass. Start from A, then for each Medium finding deduct one sub-grade level (A→B, B→C, C→D, D→F). These do accumulate across findings.
The final Anti-pattern sub-grade is the worse of the two passes
(i.e., ). Low findings never
affect the grade — mention them in the note only.
min(hard_ceiling, A − medium_count)Examples (Critical/High and Medium counts → Anti-pattern sub-grade):
- Zero Critical/High, 1 Medium → B (A − 1)
- Zero Critical/High, 3 Medium → D (A − 3)
- One C-ceiling (e.g., over-mocking), 0 Medium → C
- One C-ceiling, 2 Medium → D (, but a third Medium would tip to D)
min(C, A − 2 = C) = C - One F-finding (e.g., swallowed exception) plus any number of Medium → F
Critical (drop straight to F or D)
- No assertions at all → F (also drives Assertion sub-grade to F)
- Swallowed exceptions: (.NET), bare
try { … } catch { }(Python),except: pass(JS/TS/Java),try { … } catch (e) {}without re-panic (Go),defer recover()with no assertion (Ruby), emptyrescue StandardError(Kotlin/Swift) → Fcatch - Assert-in-catch pattern (instead of
Assert.Fail(ex.Message)) → DAssert.ThrowsException - Always-true literal assertions (,
Assert.IsTrue(true),assert True) → F (verifies nothing; also drives Assertion sub-grade to F)expect(true).toBe(true) - Self-referential / tautological assertions on bound values
(,
Assert.AreEqual(x, x)) → Dassert dto.name == dto.name - Commented-out assertions → D
High (drop one or two sub-grades)
- Wall-clock sleep used for synchronization: ,
Thread.Sleep,Task.Delay,time.sleep-based wait,setTimeout,Thread.sleep,time.Sleep,sleep,std::thread::sleep,Start-Sleep(in a unit test) → Dstd::this_thread::sleep_for - Unseeded randomness, wall-clock reads without abstraction
(,
DateTime.Now,datetime.now(),Date.now(),System.currentTimeMillis(),time.Now(),Time.now,Instant::now(),Get-Date) → Dsystem_clock::now - Hard-coded environment-dependent paths (,
C:\…, network hosts) → D/tmp/… - Ordering dependency on mutable static / package globals → D
- Broad exception assertion (,
Assert.ThrowsException<Exception>,pytest.raises(Exception)without matcher,expect(fn).toThrow(Error)without#[should_panic],expected = "…"withoutShould -Throw,-ExpectedMessage) → CEXPECT_ANY_THROW - Over-mocking: more mock setup lines than test logic, or verifying exact call sequences instead of outcomes → C
- Implementation coupling: reflection on private members, casting to internal types to access state → C
Medium (drop one sub-grade)
- Poor name: ,
Test1,TestMethod, single-word name that says nothing about scenario or expected outcome (judge against the language extension's convention) → drop one sub-gradetest - Magic values: unexplained ,
42,"foo"in arrange/assert without naming or comment → drop one sub-grade0x1234 - Giant test (>30 lines covering a single behavior) → drop one sub-grade
- Assertion messages that just repeat the assertion text → drop one sub-grade
- Missing AAA / GWT separation when the test is non-trivial → drop one sub-grade
Low (note only, no deduction)
- Unused setup/teardown hooks; print debugging left in (,
Console.WriteLine,print,console.log,System.out.println,fmt.Println,puts,dbg!,Write-Host); inconsistent naming versus siblings; leftover TODO comments. Mention in the note column but do not deduct.std::cout
对照以下目录进行扫描。反模式子等级通过两轮计算并确定组合结果:
- 硬上限轮次。每个严重或高风险发现会设置一个最高子等级(标记为F、D或C)。取所有匹配的严重/高风险发现中最差的上限——这些发现不会累积(单个F发现会将子等级上限设为F,无论其他严重/高风险发现数量多少)。
- 中等扣分轮次。从A开始,每个中等发现扣除一个子等级(A→B、B→C、C→D、D→F)。这些发现会累积。
最终反模式子等级为两轮结果中更差的那个(即)。低风险发现永远不会影响等级——仅在说明中提及。
min(硬上限, A − 中等发现数量)示例(严重/高风险和中等发现数量 → 反模式子等级):
- 无严重/高风险,1个中等 → B(A − 1)
- 无严重/高风险,3个中等 → D(A − 3)
- 一个C上限(例如过度模拟),0个中等 → C
- 一个C上限,2个中等 → C(,但第三个中等发现会降至D)
min(C, A − 2 = C) = C - 一个F发现(例如吞掉异常)加任意数量中等 → F
严重(直接降至F或D)
- 无任何断言 → F(同样会将断言子等级降至F)
- 吞掉异常:(.NET)、 bare
try { … } catch { }(Python)、except: pass(JS/TS/Java)、try { … } catch (e) {}未重新panic(Go)、defer recover()无断言(Ruby)、空rescue StandardError(Kotlin/Swift)→ Fcatch - 断言在catch中的模式(而非
Assert.Fail(ex.Message))→ DAssert.ThrowsException - 恒真字面量断言(、
Assert.IsTrue(true)、assert True)→ F(无法验证任何内容;同样会将断言子等级降至F)expect(true).toBe(true) - 绑定值的自引用/同义反复断言(、
Assert.AreEqual(x, x))→ Dassert dto.name == dto.name - 被注释掉的断言 → D
高风险(降低一到两个子等级)
- 使用挂钟睡眠进行同步:、
Thread.Sleep、Task.Delay、基于time.sleep的等待、setTimeout、Thread.sleep、time.Sleep、sleep、std::thread::sleep、Start-Sleep(在单元测试中)→ Dstd::this_thread::sleep_for - 未初始化的随机性、无抽象的挂钟读取(、
DateTime.Now、datetime.now()、Date.now()、System.currentTimeMillis()、time.Now()、Time.now、Instant::now()、Get-Date)→ Dsystem_clock::now - 硬编码依赖环境的路径(、
C:\…、网络主机)→ D/tmp/… - 对可变静态/包全局变量的顺序依赖 → D
- 宽泛的异常断言(、
Assert.ThrowsException<Exception>、pytest.raises(Exception)无匹配器、expect(fn).toThrow(Error)无#[should_panic]、expected = "…"无Should -Throw、-ExpectedMessage)→ CEXPECT_ANY_THROW - 过度模拟:模拟设置行数多于测试逻辑,或验证精确调用序列而非结果 → C
- 实现耦合:对私有成员的反射、转换为内部类型以访问状态 → C
中等(降低一个子等级)
- 命名不佳:、
Test1、TestMethod、未说明场景或预期结果的单字名称(对照语言扩展的约定判断)→ 降低一个子等级test - 魔法值:在初始化/断言中未命名或未注释的、
42、"foo"→ 降低一个子等级0x1234 - 巨型测试(>30行覆盖单一行为)→ 降低一个子等级
- 断言消息仅重复断言文本 → 降低一个子等级
- 非 trivial 测试缺少AAA/GWT分离 → 降低一个子等级
低风险(仅说明,不扣分)
- 未使用的初始化/清理钩子;遗留的打印调试代码(、
Console.WriteLine、print、console.log、System.out.println、fmt.Println、puts、dbg!、Write-Host);与同级测试命名不一致;遗留的TODO注释。在说明列中提及但不扣分。std::cout
Combining sub-grades
子等级合并
Convert sub-grades to numeric points: A=4, B=3, C=2, D=1, F=0.
- Overall score band = weighted average:
0.45 × Assertion + 0.30 × Anti-pattern + 0.25 × Structure - Map to letter:
- ≥ 3.5 → A (band 90–100)
- ≥ 2.8 → B (band 80–89)
- ≥ 2.0 → C (band 70–79)
- ≥ 1.2 → D (band 60–69)
- < 1.2 → F (band 0–59)
- The overall grade is capped at the worst sub-grade — if any sub-grade is F, the overall grade is F; if the worst sub-grade is D, the overall grade is at most D; and so on. A test that fails on any one dimension cannot earn a higher overall grade than that dimension.
Report the letter grade and the score band (not a single 0–100
number). False precision invites bikeshedding; bands keep the conversation
focused on the rubric.
将子等级转换为数值:A=4、B=3、C=2、D=1、F=0。
- 总分数区间 = 加权平均值:
0.45 × 断言强度 + 0.30 × 反模式合规性 + 0.25 × 结构与聚焦 - 映射为字母等级:
- ≥ 3.5 → A(区间90–100)
- ≥ 2.8 → B(区间80–89)
- ≥ 2.0 → C(区间70–79)
- ≥ 1.2 → D(区间60–69)
- < 1.2 → F(区间0–59)
- 最终等级受最差子等级限制——如果任何子等级为F,最终等级为F;如果最差子等级为D,最终等级最高为D;以此类推。在任一维度不合格的测试,无法获得高于该维度的最终等级。
报告字母等级和分数区间(而非0–100的单一数值)。虚假的精度会引发无意义的争论;区间能让讨论聚焦于评分标准。
Step 4: Build the note
步骤4:编写说明
The note column is one short sentence (target ≤ 120 characters). State the
single most important reason for the grade. Examples:
- A (90–100):
Clear AAA structure; equality + exception assertions on the public contract. - B (80–89):
Good assertion variety, mildly long body — consider splitting into per-condition tests. - C (70–79):
Only checks IsNotNull on the result; no value verification. - D (60–69):
Self-referential assertion: round-trip identity verifies plumbing, not transformation. - F (0–59):
No assertions — test executes the method but never verifies anything.
If a test gets A with no notable issues, the note may simply be
— do not invent weaknesses to justify the grade.
No issues found.说明列是一句简短的话(目标≤120字符)。说明等级的最重要原因。示例:
- A (90–100):
清晰的AAA结构;针对公共契约的相等性+异常断言。 - B (80–89):
断言类型丰富,方法体略长——考虑按条件拆分为多个测试。 - C (70–79):
仅检查结果的IsNotNull;无值验证。 - D (60–69):
自引用断言:往返同一性仅验证管道,而非转换逻辑。 - F (0–59):
无断言——测试执行方法但从未验证任何内容。
如果测试获得A且无明显问题,说明可简单写为——请勿为了平衡而虚构缺陷。
未发现问题。Step 5: Report
步骤5:生成报告
Produce two sections.
生成两个部分。
1. Summary
1. 摘要
A short paragraph (2–4 sentences) covering: total tests graded, grade
distribution, most common issue, and the single most important
recommendation.
简短段落(2–4句话),涵盖:评分的测试总数、等级分布、最常见问题,以及最重要的单一建议。
2. Per-test table
2. 逐测试表格
markdown
| Test | Grade | Band | Notes |
|------|-------|------|-------|
| `Namespace.ClassName.Test_Method_Condition_Expected` | A | 90–100 | Clear AAA; equality + exception assertions. |
| `Namespace.ClassName.Test_Other` | C | 70–79 | Only `IsNotNull` — no value verification. |
| `Namespace.ClassName.Test_Old` | F | 0–59 | No assertions. |Caps and ordering:
- If the table would exceed 50 rows, show all tests graded below B
first (worst to best), then a sample of the best tests, and wrap any
overflow in a collapsed block.
<details> - Within the same grade, order by file path then by method name for determinism.
- If the diff context is provided, prefix each test name with a or
(new)marker.(modified)
If multiple languages are present, produce one table per language and
prefix each section with the language name and framework.
markdown
| 测试 | 等级 | 区间 | 说明 |
|------|-------|------|-------|
| `Namespace.ClassName.Test_Method_Condition_Expected` | A | 90–100 | 清晰的AAA结构;相等性+异常断言。 |
| `Namespace.ClassName.Test_Other` | C | 70–79 | 仅包含`IsNotNull`——无值验证。 |
| `Namespace.ClassName.Test_Old` | F | 0–59 | 无断言。 |行数限制与排序:
- 如果表格行数超过50行,先显示所有等级低于B的测试(从最差到最好),然后显示部分优秀测试的样本,并将溢出部分放入折叠的块中。
<details> - 同一等级内,按文件路径然后方法名称排序,确保确定性。
- 如果提供了代码差异上下文,在每个测试名称前添加或
(新增)标记。(修改)
如果存在多种语言,为每种语言生成一个表格,并在每个部分前添加语言名称和框架。
Validation
验证清单
- Every test in the input list appears in the table (or is recorded as
).
N/A — method not found - Every grade is justified by at least one observable signal in the captured body — no speculative deductions.
- Trivial-assertion tests are flagged only when the only assertion is trivial (a null check before a meaningful assertion is not trivial).
- Exception-only tests are not penalized for low assertion count.
- Mock-call verifications and bare assertion forms count as real assertions of the appropriate category.
- Boolean assertions on meaningful properties () are not classified as always-true; only literal
Assert.IsTrue(result.IsValid)/trueconstants are.false - Self-referential assertions are flagged separately from normal equality assertions.
- Idiomatic patterns are not flagged: Go/Rust table-driven sub-tests,
pytest bare , Go
assert, JS/TSif got != want { t.Errorf(...) }.expect(mock).toHaveBeenCalledWith(...) - Async test pitfalls (un-awaited /
resolves/rejects, pytest-asyncio withoutThrowsAsync) drop the Assertion sub-grade to F.await - The summary leads with the highest-leverage observation, not a recap of the table.
- 输入列表中的每个测试都出现在表格中(或记录为)。
N/A — 方法未找到 - 每个等级都至少有一个捕获方法体中的可观察信号作为依据——无推测性扣分。
- 仅当唯一的断言是琐碎断言时,才标记琐碎断言测试(有意义断言前的空值检查不算琐碎)。
- 仅包含异常的测试不会因断言数量少而被扣分。
- 模拟调用验证和基础断言形式被视为对应类别的有效断言。
- 对有意义属性的布尔断言()不被归类为恒真;只有字面量
Assert.IsTrue(result.IsValid)/true常量才会被归类。false - 自引用断言与正常相等断言被分开标记。
- 惯用模式不会被标记:Go/Rust表格驱动子测试、pytest的bare 、Go的
assert、JS/TS的if got != want { t.Errorf(...) }。expect(mock).toHaveBeenCalledWith(...) - 异步测试陷阱(未等待的/
resolves/rejects、pytest-asyncio未加ThrowsAsync)会将断言子等级降至F。await - 摘要以最高价值的观察结果开头,而非表格的复述。
Common Pitfalls
常见陷阱
| Pitfall | Solution |
|---|---|
| Grading every test in the workspace when no list is provided | Ask the caller for the explicit list; this skill is for curated input. |
| Inflating deductions to justify the grade | Start at A; deduct only for observable issues. |
| Penalizing exception tests for low assertion count | Exception assertions are complete on their own. |
Downgrading a focused Go error-path test because it checks only | Expected-error existence is the observable contract for that scope; keep it at A unless the production contract requires a specific error identity or message. |
Treating | Only flag when the null check is the only assertion. |
| Treating any Boolean assertion as effectively assertion-free | Only always-true literals ( |
| Flagging Go/Rust table-driven loops as conditional logic | They are idiomatic; do not deduct. |
Treating pytest bare | Both are canonical; count in the correct assertion category. |
| Penalizing tests when production code is unavailable | Mark concerns about uncovered behaviors as |
| Using a fake-precise score (e.g., 87/100) | Use the score band only — 90–100, 80–89, 70–79, 60–69, 0–59. |
| Spilling a 500-row table into a PR comment | Apply the row cap from Step 5; collapse extras into |
| Re-reporting an existing finding three times under different categories | Pick the most fitting category and report once. |
| Inventing weaknesses for A-grade tests to make the note "balanced" | If a test is clean, the note may simply read |
| 陷阱 | 解决方案 |
|---|---|
| 未提供列表时对工作区中的所有测试进行评分 | 要求调用方提供明确列表;本skill仅适用于精选输入。 |
| 为了证明等级合理性而夸大扣分 | 从A开始;仅针对可观察到的问题扣分。 |
| 因断言数量少而惩罚仅包含异常的测试 | 异常断言本身是完整的。 |
因仅检查 | 预期错误的存在是该范围内的可观察契约;除非生产契约要求特定错误标识或消息,否则保持等级为A。 |
将有意义断言前的 | 仅当空值检查是唯一断言时才标记。 |
| 将任何布尔断言视为无断言 | 只有恒真字面量( |
| 将Go/Rust表格驱动循环标记为条件逻辑 | 这些是惯用写法;请勿扣分。 |
将pytest的bare | 两者都是标准写法;归入正确的断言类别。 |
| 生产代码不可用时惩罚测试 | 将未覆盖行为的担忧标记为 |
| 使用虚假精确的分数(例如87/100) | 仅使用分数区间——90–100、80–89、70–79、60–69、0–59。 |
| 将500行的表格放入PR评论 | 应用步骤5中的行数限制;将溢出部分折叠到 |
| 在不同类别下重复报告同一现有发现 | 选择最合适的类别并仅报告一次。 |
| 为A级测试虚构缺陷以让说明“平衡” | 如果测试无问题,说明可简单写为 |