ai-qa-review
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese<objective>
QA-focused code review that detects test smells, analyzes testability of application code, and identifies coverage gaps. A test that asserts `toBe(true)` and a 95%-coverage suite that only feeds happy-path input both look green and both hide bugs — this skill names the smell, cites the line, and converts "looks fine" into a mutation-score gate.
Before starting: Check for in the project root. It contains test framework conventions, naming patterns, and project-specific quality standards that calibrate review feedback.
</objective>
.agents/qa-project-context.md<objective>
以QA为核心的代码审查,可检测Test Smells(测试异味)、分析应用代码的可测试性并识别覆盖率缺口。断言`toBe(true)`的测试,以及仅输入正常路径数据却达到95%覆盖率的测试套件,表面上都显示正常,但实则隐藏着bug——本技能会明确指出问题类型、标注对应代码行,并将“看似正常”的测试转化为以变异分数为标准的质量关卡。
开始前准备: 检查项目根目录下是否存在文件。该文件包含测试框架约定、命名模式和项目特定的质量标准,用于校准审查反馈。
</objective>
.agents/qa-project-context.mdQuick Route
快速路径
Three distinct entry paths. Pick the row, then jump to the named section.
| Situation | Path | Jump to |
|---|---|---|
| PR with changed test files | Run the changed files, score them, check the diff against the PR checklist | Verification → PR Review Checklist |
| Whole suite needs a health pass | Quantify, sample, find the 3-5 systemic smells, propose lint/mutation gates | Batch Audit Process |
| Application code, "why is this hard to test?" | Flag DI / side-effect / pure-function / interface problems with before/after | Testability Analysis |
All three share the same smell vocabulary (the six buckets below) and the same Verification commands.
三种不同的入口路径。选择对应的场景,跳转至指定章节。
| 场景 | 路径 | 跳转至 |
|---|---|---|
| 包含已修改测试文件的PR | 运行已修改文件、评分、对照PR检查清单查看差异 | Verification → PR审查检查清单 |
| 整个测试套件需要健康检查 | 量化分析、抽样检测、找出3-5个系统性Test Smells、提议代码检查/变异测试关卡 | 批量审计流程 |
| 应用代码存在“难以测试”的问题 | 标记依赖注入(DI)/副作用/纯函数/接口问题,并提供前后对比方案 | 可测试性分析 |
所有路径使用相同的Test Smells分类(即下文的六个维度)和相同的Verification命令。
Discovery Questions
探索问题
First, read if present and skip any question it already answers.
.agents/qa-project-context.md- Review scope: Reviewing test code for quality, application code for testability, or both? Each triggers a different Quick Route path.
- Framework conventions: What test framework (Jest, Vitest, Playwright, pytest)? Conventions differ — nesting, fixture usage, assertion style — and the Verification commands are per-framework.
describe/it - PR review or batch audit? A PR review runs and scores only the changed files. A batch audit scans the entire suite for systemic patterns.
- Existing quality standards: Does the team have documented test conventions? Check for test rules,
.eslintrctest guidelines, or a test style guide.CONTRIBUTING.md - Known pain points: Recurring flaky tests, slow suites, unclear failures? These prioritize which smells to focus on first.
首先,若存在文件请先阅读,跳过其中已解答的问题。
.agents/qa-project-context.md- 审查范围: 是审查测试代码的质量、应用代码的可测试性,还是两者都包含?不同的范围对应不同的快速路径。
- 框架约定: 使用的测试框架是什么(Jest、Vitest、Playwright、pytest)?不同框架的约定不同——嵌套结构、fixture使用方式、断言风格——且Verification命令也因框架而异。
describe/it - PR审查还是批量审计? PR审查仅运行并评分已修改的文件,批量审计则扫描整个测试套件以发现系统性问题。
- 现有质量标准: 团队是否有文档化的测试约定?检查是否存在测试规则、
.eslintrc测试指南或测试风格指南。CONTRIBUTING.md - 已知痛点: 是否存在反复出现的不稳定测试、缓慢的测试套件、模糊的失败原因?这些问题会优先确定需要重点关注的Test Smells类型。
Core Principles
核心原则
-
Test code is production code. Apply the same quality standards: readability, maintainability, single responsibility. Test code that is hard to read is hard to trust.
-
Review what is asserted, not just what is executed. Coverage proves a line ran; it says nothing about whether a wrong value would be caught. A 95%-coverage suite ofassertions catches almost nothing. Mutation score (see Verification) measures the thing coverage can't.
toBeTruthy -
Testability review prevents test debt. Reviewing application code for testability catches design problems before they force awkward test workarounds. If code is hard to test, it is usually hard to maintain.
-
Codify patterns, not just knowledge. Turn recurring review feedback into lint rules, custom ESLint plugins, or shared fixtures. Reviews that repeat the same feedback indicate missing automation.
-
Smells are symptoms, not verdicts. A test smell indicates a potential problem; context decides whether it is actually harmful. A long test for a complex workflow may be appropriate. A mock-heavy test for a boundary may be correct.
-
Actionable feedback only. Every review comment must include what is wrong, why it matters, and how to fix it. "This test is bad" is not actionable. "This test uses sleep-based waiting which causes flakiness — replace with an explicit wait condition" is.
-
测试代码也是生产代码。 应用相同的质量标准:可读性、可维护性、单一职责。难以阅读的测试代码也难以让人信任。
-
审查断言内容,而非仅执行内容。 覆盖率只能证明代码行被执行过,但无法说明错误值是否会被捕获。一个由断言组成的95%覆盖率测试套件几乎无法发现任何问题。变异分数(详见Verification部分)可以衡量覆盖率无法覆盖的维度。
toBeTruthy -
可测试性审查预防测试债务。 审查应用代码的可测试性可以在设计问题导致笨拙的测试解决方案之前就发现并解决。如果代码难以测试,通常也难以维护。
-
将模式代码化,而非仅依赖知识。 将反复出现的审查反馈转化为lint规则、自定义ESLint插件或共享fixture。重复出现相同反馈的审查表明缺少自动化机制。
-
Test Smells是症状,而非结论。 Test Smells表明存在潜在问题,但具体是否有害需要结合上下文判断。针对复杂工作流的长测试可能是合理的,针对边界的重度Mock测试也可能是正确的。
-
仅提供可执行的反馈。 每条审查评论必须包含问题所在、影响原因以及修复方案。“这个测试很差”不是可执行的反馈,“该测试使用基于睡眠的等待方式会导致不稳定——请替换为明确的等待条件”才是。
Test Smell Buckets
Test Smells分类维度
Six dimensions. Each smell is categorized by the dimension it affects and links to a specific review action. Full SMELL/FIX code for every catalogued smell lives in — keep the inline pointers prominent; the before/after code is the load-bearing part.
references/smell-examples.md六个维度。每个Test Smell都按其影响的维度分类,并链接到具体的审查操作。所有已归类的Test Smell的完整SMELL/FIX代码示例都位于中——请突出显示内联指向,前后对比代码是核心内容。
references/smell-examples.mdReadability Smells
可读性Test Smells
Problems that make tests hard to understand at a glance.
导致测试难以快速理解的问题。
Obscure Setup
模糊的初始化设置
What it looks like: 30+ lines of object construction with irrelevant fields drowning the test intent. The reader cannot tell which fields matter for the assertion.
Fix: Extract to factories. Only test-relevant data should appear in the test body: instead of constructing full user/product/order objects inline.
buildOrder({ items: [buildItem({ weight: 2.5, quantity: 2 })] })Review action: Request factory extraction.
表现: 30行以上的对象构造代码,无关字段掩盖了测试意图。读者无法分辨哪些字段对断言有影响。
修复方案: 提取到工厂函数中。测试体中仅保留与测试相关的数据:使用替代在测试内联构造完整的用户/产品/订单对象。
buildOrder({ items: [buildItem({ weight: 2.5, quantity: 2 })] })审查操作: 要求提取工厂函数。
Mystery Guest
神秘依赖
What it looks like: — the test depends on external data the reader cannot see. They must open another file to understand the assertion.
loadFixture('report.json')Fix: Inline the test-relevant data or use descriptively named fixtures. The reader should understand the test without opening other files.
Review action: Request inline data or descriptive fixture names.
表现: ——测试依赖读者无法直接查看的外部数据,必须打开另一个文件才能理解断言内容。
loadFixture('report.json')修复方案: 内联与测试相关的数据,或使用具有描述性名称的fixture。读者无需打开其他文件即可理解测试内容。
审查操作: 要求内联数据或使用描述性fixture名称。
Duplicate Assertions
重复断言
What it looks like: Multiple tests assert the same behavior with varying specificity (, , ). Three tests, one behavior.
toBe('Alice')toHaveProperty('name')toBeDefined()Review action: Request consolidation. Keep the most specific assertion. Redundant tests increase maintenance cost without increasing confidence.
表现: 多个测试以不同的特异性断言相同的行为(、、)。三个测试,验证同一个行为。
toBe('Alice')toHaveProperty('name')toBeDefined()审查操作: 要求合并测试。保留最具体的断言。冗余测试会增加维护成本,却不会提升测试信心。
Reliability Smells
可靠性Test Smells
Problems that cause tests to fail intermittently or in unexpected environments.
导致测试间歇性失败或在非预期环境中失败的问题。
Sleep-Based Waiting
基于睡眠的等待
What it looks like: , , used for synchronization. See for the SMELL/FIX pair (replace with an explicit wait).
setTimeoutsleep()waitForTimeout()references/smell-examples.mdwaitForTimeouttoBeVisibleReview action: Reject. Sleep-based waiting is never acceptable. Require explicit wait conditions.
表现: 使用、、进行同步。详见中的SMELL/FIX示例(将替换为明确的等待)。
setTimeoutsleep()waitForTimeout()references/smell-examples.mdwaitForTimeouttoBeVisible审查操作: 拒绝此类代码。基于睡眠的等待方式绝不被允许,要求使用明确的等待条件。
Order Dependency
执行顺序依赖
What it looks like: Tests pass when run together but fail in isolation or different order. See for the SMELL/FIX pair (each test creating its own preconditions).
references/smell-examples.mdReview action: Request data isolation. Each test must create its own preconditions.
表现: 测试一起运行时通过,但单独运行或改变顺序时失败。详见中的SMELL/FIX示例(每个测试创建自己的前置条件)。
references/smell-examples.md审查操作: 要求数据隔离。每个测试必须创建自己的前置条件。
External Service Coupling
外部服务耦合
What it looks like: Tests call real external APIs (payment gateways, email providers, third-party services). See for the SMELL/FIX pair (mocking the service boundary).
references/smell-examples.mdReview action: Request mock or fake at the service boundary. External calls belong in integration/contract tests, not unit tests.
表现: 测试调用真实的外部API(支付网关、邮件服务商、第三方服务)。详见中的SMELL/FIX示例(Mock服务边界)。
references/smell-examples.md审查操作: 要求在服务边界处使用Mock或Fake。外部调用应属于集成/契约测试,而非单元测试。
Diagnostic Smells
诊断性Test Smells
Problems that make test failures hard to understand and debug.
导致测试失败原因难以理解和调试的问题。
Weak Assertion Messages
薄弱的断言信息
What it looks like: Assertion fails with no context about what was expected or why. See for the SMELL/FIX pair (replacing with specific assertions like that surface the offending value).
references/smell-examples.mdtoBe(true)expect(result.errors).toEqual([])Review action: Request stronger assertions with diagnostic value. The failure message should explain the problem without reading the test source.
表现: 断言失败时没有提供预期结果或失败原因的上下文。详见中的SMELL/FIX示例(将替换为具体的断言,如,以便显示错误值)。
references/smell-examples.mdtoBe(true)expect(result.errors).toEqual([])审查操作: 要求使用具有诊断价值的更强断言。失败消息应无需查看测试源代码即可解释问题。
Multiple Failure Causes Per Test
单个测试存在多个失败原因
What it looks like: A single test covers multiple independent behaviors. When it fails, you do not know which behavior broke. See for the SMELL/FIX pair (splitting a lifecycle test into one-behavior-per-test).
references/smell-examples.mdReview action: Request test splitting. Each test should have one reason to fail.
表现: 单个测试覆盖多个独立行为。当测试失败时,无法确定是哪个行为出了问题。详见中的SMELL/FIX示例(将生命周期测试拆分为每个测试验证一个行为)。
references/smell-examples.md审查操作: 要求拆分测试。每个测试应只有一个失败原因。
Design Smells
设计性Test Smells
Problems in test architecture that increase maintenance cost.
测试架构中增加维护成本的问题。
Conditional Test Logic
测试体中的条件逻辑
What it looks like: , , ternaries, or loops inside test bodies. Branching logic in a test is itself untested — you cannot tell which cases actually ran. See for the SMELL/FIX pair (converting a branching loop into ).
if/elseswitchforreferences/smell-examples.mdit.eachReview action: Request parameterized tests ( / ). Conditional logic in tests hides which cases are actually verified.
it.eachtest.each表现: 测试体中存在、、三元表达式或循环。测试中的分支逻辑本身未被测试——无法确定哪些分支实际被执行。详见中的SMELL/FIX示例(将分支循环转换为)。
if/elseswitchforreferences/smell-examples.mdit.each审查操作: 要求使用参数化测试( / )。测试中的条件逻辑会隐藏实际验证的用例。
it.eachtest.eachGiant Fixtures
巨型Fixture
What it looks like: A or fixture that sets up 20+ objects for every test, even though each test uses 2-3 of them. See for the SMELL/FIX pair (replacing a monolithic with per-test inline setup).
beforeEachreferences/smell-examples.mdbeforeEachReview action: Request inline setup. Move shared setup to factories, not monolithic blocks.
beforeEach表现: 或fixture为每个测试设置20个以上的对象,尽管每个测试仅使用其中2-3个。详见中的SMELL/FIX示例(将单体替换为每个测试的内联设置)。
beforeEachreferences/smell-examples.mdbeforeEach审查操作: 要求使用内联设置。将共享设置移至工厂函数,而非单体块。
beforeEachOver-Mocking
过度Mock
What it looks like: Every collaborator is mocked, including simple value objects and pure functions. See for the SMELL/FIX pair (dropping a mock of the very function under test).
references/smell-examples.mdReview action: Request removal of unnecessary mocks. Mock boundaries, not internals.
表现: 对所有协作对象进行Mock,包括简单的值对象和纯函数。详见中的SMELL/FIX示例(移除对被测函数本身的Mock)。
references/smell-examples.md审查操作: 要求移除不必要的Mock。仅Mock边界,而非内部实现。
AI-Generated Test Smells
AI生成的Test Smells
When the test code came from a coding agent (Claude Code, Codex, Cursor, Copilot), the smell taxonomy is the same — but a few signature failures recur often enough to deserve their own pass.
| Smell | Detection |
|---|---|
| Hallucinated locator | Run the test against a real page once. If the locator never matches, the LLM invented a |
| Fabricated import | Static-check every imported symbol — does the file or package actually export it? LLMs invent plausible APIs ( |
| Generic test data | |
| Closed AI loop | Both implementation and tests authored by the same agent in the same session. The tests just describe what the agent produced; they don't constrain it. Pair the agent's tests with at least one human-authored boundary test, or use TDD (test-first) per |
| Project-convention drift | Page Object, fixture, naming, or assertion style different from the rest of the suite. AI-generated code rarely matches local conventions out of the box. |
For first-time test generation patterns and the Step-7 review checklist, cross-link . For AI-system eval suites (the equivalent of ESLint for prompts), wire each tool's CLI runner — , (Apache 2.0), Ragas / experiments (Apache 2.0) — as quality gates parallel to your test runner.
ai-test-generationpromptfoo evaldeepeval test runragas evaluatePromptfoo ownership note: Promptfoo was acquired by OpenAI (announced 9 Mar 2026). The core stays MIT-licensed, open source, and model-agnostic; red-team capabilities are being folded into OpenAI Frontier.is still the correct quality-gate command — just expect the vendor to be OpenAI going forward.promptfoo eval
当测试代码来自编码Agent(Claude Code、Codex、Cursor、Copilot)时,Test Smells的分类标准相同,但有一些常见的典型问题值得单独检查。
| Test Smell | 检测方式 |
|---|---|
| 幻觉定位器 | 在真实页面上运行一次测试。如果定位器从未匹配到元素,说明LLM生成了一个不存在的 |
| 虚构导入 | 静态检查所有导入的符号——对应的文件或包是否真的导出该符号?LLM会生成看似合理的API(如 |
| 通用测试数据 | 使用 |
| 闭环AI生成 | 实现代码和测试代码由同一个Agent在同一会话中生成。测试仅描述Agent生成的内容,并未对其进行约束。请将Agent生成的测试与至少一个人工编写的边界测试结合,或按照 |
| 项目约定偏离 | Page Object、fixture、命名或断言风格与测试套件的其他部分不一致。AI生成的代码通常无法直接匹配本地约定。 |
有关首次测试生成模式和Step-7审查清单,请交叉参考。对于AI系统评估套件(相当于针对提示词的ESLint),请将各工具的CLI运行器——、(Apache 2.0)、Ragas / experiments(Apache 2.0)——作为与测试运行器并行的质量关卡。
ai-test-generationpromptfoo evaldeepeval test runragas evaluatePromptfoo归属说明: Promptfoo于2026年3月9日被OpenAI收购。核心代码仍保持MIT许可、开源且模型无关;红队能力将整合到OpenAI Frontier中。仍是正确的质量关卡命令——只是后续供应商将变为OpenAI。promptfoo eval
Coverage Smells
覆盖率Test Smells
Problems that leave gaps in what is verified.
导致验证范围存在缺口的问题。
Happy Path Only
仅覆盖正常路径
What it looks like: Every test provides valid input and expects success. No error paths tested. See for the SMELL/FIX pair (adding zero, max, negative, and boundary cases to a discount calculator).
references/smell-examples.mdReview action: Request missing scenarios. Use the BOUNDARY framework: Boundary values, Null/empty, Duplicates, Ordering, Range limits.
表现: 所有测试都提供有效输入并预期成功结果,未测试错误路径。详见中的SMELL/FIX示例(为折扣计算器添加零值、最大值、负值和边界用例)。
references/smell-examples.md审查操作: 要求补充缺失的场景。使用BOUNDARY框架:边界值、空值/空对象、重复值、排序、范围限制。
Missing Boundary Cases
缺失边界用例
What it looks like: Tests for "normal" values (5 items) but not for 0, 1, max, or max+1. Use to cover boundaries explicitly: empty collection, single item, exact page size, one over, large set.
it.eachReview action: Request boundary tests. Every numeric parameter, string length, and collection size has boundaries to test.
表现: 测试“正常”值(如5个条目),但未测试0、1、最大值或最大值+1。使用明确覆盖边界情况:空集合、单个条目、精确页面大小、超出一个、大型集合。
it.each审查操作: 要求添加边界测试。每个数值参数、字符串长度和集合大小都有需要测试的边界。
Missing Error/Negative Cases
缺失错误/异常用例
What it looks like: No tests for what happens when things go wrong — network failures, invalid input, permission denied, concurrent modification.
Review action: For each happy path test, ask: "What is the corresponding failure mode?" Request tests for the failure.
表现: 未测试故障场景——网络失败、无效输入、权限拒绝、并发修改。
审查操作: 针对每个正常路径测试,思考:“对应的故障模式是什么?”要求添加针对故障场景的测试。
Testability Analysis
可测试性分析
When reviewing application code, assess whether it is structured for testability. Each subsection has a hard-to-test vs. testable before/after in .
references/testability-refactors.md审查应用代码时,评估其结构是否便于测试。每个小节的“难以测试”与“可测试”前后对比示例都位于中。
references/testability-refactors.mdDependency Injection
依赖注入
Flag classes that instantiate dependencies directly (, inside methods). Suggest constructor injection so tests can substitute mocks/fakes. See .
new PostgresDatabase()new StripeClient()references/testability-refactors.md标记在方法内部直接实例化依赖的类(如、)。建议使用构造函数注入,以便测试时可以替换为Mock/Fake。详见。
new PostgresDatabase()new StripeClient()references/testability-refactors.mdSide Effect Isolation
副作用隔离
Flag functions that mix pure calculation with I/O (email, logging, analytics). Extract the calculation as a pure function, then call it from the side-effectful orchestrator. See the before/after in .
calcTotalreferences/testability-refactors.md标记将纯计算与I/O操作(邮件、日志、分析)混合的函数。将计算部分提取为纯函数,然后在处理副作用的协调器中调用该纯函数。详见中的前后对比示例。
references/testability-refactors.mdcalcTotalPure Function Extraction
纯函数提取
Look for validation, transformation, and business rules buried inside request handlers. If logic is inline in , it cannot be unit-tested without spinning up an HTTP server. Extract it as a standalone function. See the before/after in .
app.post('/api/orders', ...)shippingForreferences/testability-refactors.md查找嵌入在请求处理器中的验证、转换和业务规则。如果逻辑内联在中,则无法在不启动HTTP服务器的情况下进行单元测试。将其提取为独立函数。详见中的前后对比示例。
app.post('/api/orders', ...)references/testability-refactors.mdshippingForInterface Segregation
接口隔离
Flag classes that depend on broad interfaces (entire ) when they only use 2-3 methods. Suggest a narrow interface with only the methods actually used, making test doubles trivial to implement. See .
PrismaClientreferences/testability-refactors.md标记依赖宽泛接口(如完整的)但仅使用其中2-3个方法的类。建议使用仅包含实际使用方法的窄接口,使测试替身的实现变得简单。详见。
PrismaClientreferences/testability-refactors.mdReview Workflow
审查工作流
PR Review Checklist
PR审查检查清单
For each test file in a PR, check systematically:
markdown
undefined针对PR中的每个测试文件,系统地检查以下内容:
markdown
undefinedTest Quality Review
测试质量审查
Readability
可读性
- Can I understand what each test verifies in under 10 seconds?
- Is setup minimal and test-relevant?
- Are test names descriptive: "should [behavior] when [condition]"?
- 我能否在10秒内理解每个测试验证的内容?
- 初始化设置是否最小化且仅与测试相关?
- 测试名称是否具有描述性:"should [行为] when [条件]"?
Reliability
可靠性
- No sleep/waitForTimeout/setTimeout for synchronization?
- No shared mutable state between tests?
- No dependency on test execution order?
- No calls to real external services?
- 是否未使用sleep/waitForTimeout/setTimeout进行同步?
- 测试之间是否不存在共享可变状态?
- 是否不依赖测试执行顺序?
- 是否未调用真实的外部服务?
Diagnostic Value
诊断价值
- Will failures produce messages that identify the problem?
- Does each test have one reason to fail?
- Are assertions specific (not toBeTruthy/toBeDefined)?
- 失败时是否会生成能识别问题的消息?
- 每个测试是否只有一个失败原因?
- 断言是否具体(而非toBeTruthy/toBeDefined)?
Design
设计
- No conditional logic (if/else/switch/for) in test bodies?
- Fixtures/setup proportional to what each test needs?
- Mocking limited to external boundaries?
- Parameterized tests (it.each) used for data-driven scenarios?
- 测试体中是否不存在条件逻辑(if/else/switch/for)?
- Fixture/设置是否与每个测试的需求匹配?
- Mock是否仅用于外部边界?
- 是否使用参数化测试(it.each)处理数据驱动的场景?
AI-Generated (if applicable)
AI生成(如适用)
- Locators verified against a real page (no hallucinated data-testid)?
- Imports resolve (no fabricated APIs)?
- Project data factory used, not test@test.com / John Doe?
- 定位器是否已在真实页面上验证(无幻觉data-testid)?
- 导入是否可解析(无虚构API)?
- 是否使用项目的数据工厂函数,而非test@test.com / John Doe等通用数据?
Coverage
覆盖率
- Happy path AND error/negative paths tested?
- Boundary values tested (0, 1, max, max+1)?
- Edge cases: empty, null, duplicate, concurrent?
undefined- 是否同时测试了正常路径和错误/异常路径?
- 是否测试了边界值(0、1、最大值、最大值+1)?
- 是否测试了边缘场景:空值、Null、重复、并发?
undefinedBatch Audit Process
批量审计流程
For a full test suite audit:
- Quantify: Count tests by type (unit/integration/E2E), framework, and directory.
- Sample: Review 10-20% of test files, prioritizing the largest and most recently changed.
- Pattern: Identify the 3-5 most common smells across the sample.
- Prioritize: Rank by impact: reliability smells > diagnostic smells > design smells > readability smells.
- Automate: For each common smell, determine if an ESLint rule or a mutation-score gate can catch it automatically.
- Report: Document findings (one row per file reviewed) with specific examples, suggested fixes, severity (high/medium/low), and estimated effort.
针对完整测试套件的审计:
- 量化分析: 按测试类型(单元/集成/E2E)、框架和目录统计测试数量。
- 抽样检测: 审查10-20%的测试文件,优先选择最大和最近修改的文件。
- 模式识别: 找出样本中最常见的3-5个Test Smells。
- 优先级排序: 按影响程度排序:可靠性Test Smells > 诊断性Test Smells > 设计性Test Smells > 可读性Test Smells。
- 自动化实现: 针对每个常见的Test Smells,确定是否可以通过ESLint规则或变异分数关卡自动检测。
- 报告输出: 记录发现的问题(每个被审查文件对应一行),包含具体示例、建议修复方案、严重程度(高/中/低)和预估工作量。
Prompt Templates
提示词模板
Three prompt patterns for AI-assisted review:
-
Review test quality: "Check this test file for readability, reliability, diagnostic, design, AI-generated, and coverage smells. For each issue: name the smell, cite the line, explain why it matters, and provide a fix."
-
Identify coverage gaps: "Given this application code and its existing tests, identify missing scenarios across happy path, error handling, boundaries, edge cases, concurrency, and security. Prioritize as P0/P1/P2."
-
Testability improvements: "Review this application code for hard-coded dependencies, mixed side effects, extractable pure functions, and overly broad interfaces. Show current vs. refactored code."
三种用于AI辅助审查的提示词模式:
-
测试质量审查: "检查此测试文件的可读性、可靠性、诊断性、设计性、AI生成及覆盖率维度的Test Smells。针对每个问题:命名Test Smell类型、标注对应代码行、解释影响原因并提供修复方案。"
-
识别覆盖率缺口: "给定此应用代码及其现有测试,识别正常路径、错误处理、边界、边缘场景、并发和安全方面的缺失用例。按P0/P1/P2优先级排序。"
-
可测试性改进: "审查此应用代码中的硬编码依赖、混合副作用、可提取的纯函数和过于宽泛的接口。展示当前代码与重构后的代码对比。"
Anti-Patterns
反模式
-
Reviewing test code with production-code standards only. Test code has additional quality dimensions (reliability, diagnostics, coverage) that production-code linters do not check. Apply the six smell buckets, not just "clean code" principles.
-
Flagging every smell without context. A 50-line test for a complex state machine is not obscure setup — it is necessary complexity. Evaluate smells against the behavior being tested.
-
Suggesting mocks for everything. Over-mocking is itself a smell. Do not recommend mocking pure functions, value objects, or fast in-process collaborators. Mock boundaries: network, database, filesystem, clock.
-
Focusing on coverage percentage over coverage quality. 95% line coverage with only happy-path tests is worse than 75% coverage that includes error paths and boundaries. Review what is asserted, not just what is executed — and back it with mutation score.
-
Reviewing without running. Static analysis misses runtime issues. Run the suite (see Verification), check for flakiness with repeated runs, and check execution time. A passing suite that takes 20 minutes has a performance smell.
-
One-time review without follow-up. Test quality degrades over time. Establish a recurring review cadence or automated quality gates (lint rule, mutation threshold) that catch regression.
-
仅用生产代码标准审查测试代码。 测试代码有额外的质量维度(可靠性、诊断性、覆盖率),而生产代码的lint工具不会检查这些维度。请应用六个Test Smells分类维度,而非仅“整洁代码”原则。
-
不结合上下文标记所有Test Smells。 针对复杂状态机的50行测试并非模糊的初始化设置——这是必要的复杂度。请结合被测行为评估Test Smells。
-
建议对所有内容进行Mock。 过度Mock本身就是一种Test Smell。不建议对纯函数、值对象或快速进程内协作对象进行Mock。仅Mock边界:网络、数据库、文件系统、时钟。
-
关注覆盖率百分比而非覆盖率质量。 仅覆盖正常路径的95%行覆盖率,不如包含错误路径和边界场景的75%覆盖率有价值。审查断言内容,而非仅执行内容——并通过变异分数提供支撑。
-
不运行测试就进行审查。 静态分析会遗漏运行时问题。运行测试套件(详见Verification),通过重复运行检查是否存在不稳定问题,并记录执行时间。一个需要20分钟才能完成的通过测试套件存在性能问题。
-
一次性审查而不跟进。 测试质量会随时间下降。建立定期审查机制或自动化质量关卡(lint规则、变异分数阈值)以捕获回归问题。
Verification
Verification(验证)
Run before you start commenting — these are the runtime checks the skill insists on, made concrete. Scope them to the PR's changed test files in PR review; run the whole suite in a batch audit.
- Run the suite once. Confirm it is green before reviewing — never review red or skipped tests as if they pass.
- Vitest: · Jest:
npx vitest run <files>· Playwright:npx jest <files>· pytest:npx playwright test <files>pytest <files>
- Vitest:
- Repeat to surface flakiness. A test that passes once and fails on the next run is the reliability smell, not a fluke.
- Vitest: looped, or
npx vitest run --retry=0 <files>for i in 1 2 3; do npx vitest run <files> || break; done - Jest: (or
npx jest <files> && npx jest <files> && npx jest <files>repeat)jest-circus - Playwright:
npx playwright test --repeat-each=3 <files> - pytest: (pytest-repeat) or
pytest --count=3 <files>vs random order to catch order dependencypytest -p no:randomly
- Vitest:
- Capture per-test timing. A 20-minute suite has a performance smell.
- Vitest: (prints per-test duration) · Jest:
--reporter=verbose· Playwright:--verbose· pytest:--reporter=list--durations=10
- Vitest:
- Mutation score — the objective backstop. For the qualitative smells you can't eyeball at scale (Closed AI loop, weak assertions), run a mutation runner and read the score. AI-generated tests under ~60% mutation score are not constraining the implementation. Full tooling, thresholds, and config in .
references/mutation-testing.md- JS/TS: · Java: PIT
npx stryker run· Rust:mvn ... mutationCoverage· Python:cargo mutantsmutmut run
- JS/TS:
Output of steps 1-3 plus the mutation score is the evidence behind every "reliability"/"diagnostic" finding in the report.
在开始评论前执行以下操作——这些是本技能要求的运行时检查,具体如下。PR审查时仅针对PR中修改的测试文件;批量审计时运行整个测试套件。
- 运行一次测试套件。 在审查前确认测试全部通过——绝不要将失败或跳过的测试视为通过。
- Vitest: · Jest:
npx vitest run <files>· Playwright:npx jest <files>· pytest:npx playwright test <files>pytest <files>
- Vitest:
- 重复运行以发现不稳定问题。 一次通过但下次运行失败的测试属于可靠性Test Smell,而非偶然情况。
- Vitest: 循环执行,或执行
npx vitest run --retry=0 <files>for i in 1 2 3; do npx vitest run <files> || break; done - Jest: (或使用
npx jest <files> && npx jest <files> && npx jest <files>重复运行)jest-circus - Playwright:
npx playwright test --repeat-each=3 <files> - pytest: (需安装pytest-repeat)或对比
pytest --count=3 <files>与随机执行顺序以发现顺序依赖问题pytest -p no:randomly
- Vitest: 循环执行
- 捕获每个测试的执行时间。 需要20分钟才能完成的测试套件存在性能问题。
- Vitest: (显示每个测试的执行时长) · Jest:
--reporter=verbose· Playwright:--verbose· pytest:--reporter=list--durations=10
- Vitest:
- 变异分数——客观的支撑标准。 对于无法大规模直观判断的定性Test Smells(闭环AI生成、薄弱断言),运行变异测试工具并查看分数。AI生成的测试变异分数低于约60%时,无法对实现代码形成约束。完整的工具、阈值和配置详见。
references/mutation-testing.md- JS/TS: · Java: PIT
npx stryker run· Rust:mvn ... mutationCoverage· Python:cargo mutantsmutmut run
- JS/TS:
步骤1-3的输出加上变异分数,是报告中所有“可靠性”/“诊断性”结论的依据。
Done When
完成标准
- The findings artifact exists with one row per reviewed file, each row carrying a severity rating (high/medium/low). (file exists, row count == files reviewed)
- Every smell dimension that applies to the reviewed code is covered: readability, reliability, diagnostic, design, AI-generated, coverage. (six headings present in the report; "N/A" allowed, blank not)
- Each high-severity finding has an actionable remediation step (what + why + fix), not just a description.
- Verification ran: the suite executed at least 3x green (no flaky failures) and per-test timing captured; for AI-generated suites, a mutation score is recorded.
- At least one recurring smell was converted to an automated gate — an ESLint rule, a CI check, or a mutation-score threshold committed — or the report explicitly states none was warranted.
- 生成包含每个被审查文件对应条目的结果文档,每条包含严重程度评级(高/中/低)。(文件存在,条目数等于被审查文件数)
- 覆盖所有适用于被审查代码的Test Smells维度:可读性、可靠性、诊断性、设计性、AI生成、覆盖率。(报告中包含六个标题;允许标注“不适用”,但不能空白)
- 每个高严重程度的结论都包含可执行的修复步骤(问题+原因+方案),而非仅描述。
- 已执行Verification:测试套件至少运行3次且全部通过(无不稳定失败),并捕获了每个测试的执行时间;对于AI生成的测试套件,记录了变异分数。
- 至少将一个反复出现的Test Smells转化为自动化关卡——提交ESLint规则、CI检查或变异分数阈值——或报告中明确说明无需自动化。
Reference Files (in references/
)
references/参考文件(位于references/
目录下)
references/- smell-examples.md — Full SMELL/FIX code for every catalogued smell across reliability, diagnostic, design, and coverage dimensions.
- testability-refactors.md — Hard-to-test vs. testable before/after for all four testability subsections: dependency injection, side effect isolation, pure function extraction, interface segregation.
- mutation-testing.md — Tooling (Stryker/PIT/cargo-mutants/mutmut), thresholds, Stryker config, and the AI-loop / weak-assertion gate.
- smell-examples.md —— 可靠性、诊断性、设计性和覆盖率维度下所有已归类Test Smell的完整SMELL/FIX代码示例。
- testability-refactors.md —— 四个可测试性小节的“难以测试”与“可测试”前后对比示例:依赖注入、副作用隔离、纯函数提取、接口隔离。
- mutation-testing.md —— 工具(Stryker/PIT/cargo-mutants/mutmut)、阈值、Stryker配置,以及AI闭环/薄弱断言关卡。
Related Skills
相关技能
- unit-testing — Framework-specific patterns (Jest, Vitest, pytest) that inform what "good" looks like for each framework.
- shift-left-testing — Pre-commit hooks and IDE integration that catch test smells before review.
- coverage-analysis — Interpreting coverage reports to find meaningful gaps, not just percentage targets.
- ai-test-generation — Generated tests need review too. Apply these smell checks to AI-generated test code.
- test-reliability — Reliability smells (sleep-based waits, order dependency) overlap with flaky test patterns.
- unit-testing —— 特定框架的模式(Jest、Vitest、pytest),定义了每个框架下“优质测试”的标准。
- shift-left-testing —— 提交前钩子和IDE集成,可在审查前发现Test Smells。
- coverage-analysis —— 解读覆盖率报告以发现有意义的缺口,而非仅关注百分比目标。
- ai-test-generation —— 生成的测试也需要审查。将这些Test Smells检查应用于AI生成的测试代码。
- test-reliability —— 可靠性Test Smells(基于睡眠的等待、执行顺序依赖)与不稳定测试模式重叠。