unit-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese<objective>
Write unit tests that fail when the code is wrong and pass when it is right — nothing
weaker. A test that mocks every collaborator stays green while the integration is
broken; the doubles taxonomy below stops that. A `coverageThreshold` typo (or the
plural `coverageThresholds`, which Jest silently ignores) lets 40%-covered code ship
on a green pipeline; the config and Verification sections below make the gate actually
fire. This skill covers Jest, Vitest, and pytest: doubles, coverage gating, snapshots,
fake timers, and mutation testing as a behavior check on top of coverage.
</objective>
<objective>
编写的单元测试需满足:代码错误时测试失败,代码正确时测试通过——标准不能降低。如果一个测试将所有协作对象都mock掉,那么即使集成逻辑已损坏,测试仍会显示通过;下文的测试替身分类可避免这种情况。`coverageThreshold`的拼写错误(或复数形式`coverageThresholds`,Jest会静默忽略)会让覆盖率仅40%的代码通过绿色流水线发布;下文的配置与验证部分可确保门禁真正生效。本技能涵盖 Jest、Vitest 和 pytest:测试替身、覆盖率门禁、快照测试、假计时器,以及作为覆盖率之上行为校验的突变测试。
</objective>
Discovery Questions
探索问题
Check first — if it exists, use it and skip anything answered there.
.agents/qa-project-context.md- Framework: Jest, Vitest, or pytest? Check or
package.json. The runner decides config keys and mock APIs.pyproject.toml - Coverage tooling: Already configured? Look for ,
jest.config.*,vitest.config.*,.nycrc. Determines whether you add the gate or just tune it.[tool.coverage] - Mocking strategy: Manual mocks, auto-mocking, or dependency injection? Check for dirs or DI containers — this sets which doubles you reach for.
__mocks__/ - Conventions: Co-location (next to source) or a
*.test.ts/__tests__tree? Match what exists; don't introduce a third location.tests/
首先查看文件——如果存在,使用其中的信息并跳过已解答的问题。
.agents/qa-project-context.md- 测试框架: 使用 Jest、Vitest 还是 pytest?查看或
package.json文件。测试运行器决定了配置项和mock API的使用方式。pyproject.toml - 覆盖率工具: 是否已配置?查找、
jest.config.*、vitest.config.*、.nycrc配置。这将决定你是需要添加门禁还是仅调整现有配置。[tool.coverage] - Mock策略: 手动mock、自动mock还是依赖注入?查找目录或DI容器——这将决定你选择哪种测试替身。
__mocks__/ - 代码约定: 测试文件与源代码同目录(放在源码旁)还是单独的
*.test.ts/__tests__目录?遵循项目现有约定,不要引入第三种存放位置。tests/
Core Principles
核心原则
1. Test behavior, not implementation. Verify what code does, not how. Refactoring internals should not break tests.
typescript
// Bad — implementation detail // Good — observable behavior
expect(svc._cache.size).toBe(3); expect(svc.getUser("abc")).toEqual({ id: "abc", name: "Alice" });2. Fast, isolated, deterministic. No network/disk/DB. No shared mutable state. No uncontrolled or — freeze them with fake timers and seeded values.
Date.now()Math.random()3. Arrange-Act-Assert. One clear shape per test.
typescript
it("should apply discount for orders over $100", () => {
// Arrange
const order = createOrder({ subtotal: 150 });
const svc = new DiscountService(0.1);
// Act
const result = svc.apply(order);
// Assert
expect(result.total).toBe(135);
});4. One assertion concept per test. Multiple calls are fine when they verify the same concept.
expect5. Descriptive names. , not .
"should [behavior] when [condition]""test calculateTotal"1. 测试行为,而非实现细节。 验证代码的功能,而非实现方式。重构内部逻辑不应导致测试失败。
typescript
// 不良示例——依赖实现细节 // 良好示例——验证可观测行为
expect(svc._cache.size).toBe(3); expect(svc.getUser("abc")).toEqual({ id: "abc", name: "Alice" });2. 快速、独立、可预测。 不依赖网络/磁盘/数据库。无共享可变状态。避免不受控的或——使用假计时器和种子值固定这些变量。
Date.now()Math.random()3. Arrange-Act-Assert 模式。 每个测试遵循清晰的三段式结构。
typescript
it("should apply discount for orders over $100", () => {
// Arrange(准备)
const order = createOrder({ subtotal: 150 });
const svc = new DiscountService(0.1);
// Act(执行)
const result = svc.apply(order);
// Assert(断言)
expect(result.total).toBe(135);
});4. 每个测试验证一个核心逻辑点。 当多个调用验证同一逻辑时,是允许的。
expect5. 测试名称具备描述性。 使用「should [行为] when [条件]」格式,而非「test calculateTotal」这类模糊名称。
Framework-Specific Patterns
框架专属模式
The full setup/teardown, mocking, spying, timer, in-source, and monorepo examples for
each runner live in . Below is what is current and what to
reach for; copy the code from the reference.
references/patterns.md各运行器的完整初始化/清理、mock、spy、计时器、源码内测试、单仓库示例均存于。以下是当前主流版本及推荐用法;代码示例请参考该文件。
references/patterns.mdJest
Jest
Current is Jest 30.x (30.4.2, May 2026). Jest 30 added ,
support, Temporal-aware fake timers, and . If the
code under test uses the Temporal API or time-zone logic, Jest 30's Temporal-aware fake
timers remove a class of brittle setup.
--collect-testsjest.config.mtsclearMocksOnScopeReach for: for module boundaries ( for partial mocks),
to wrap a real method, for typed mocks, and
for time. See § Jest.
jest.mock()jest.requireActualjest.spyOn()jest.Mocked<T>jest.useFakeTimers()references/patterns.md当前主流版本为 Jest 30.x(30.4.2,2026年5月)。Jest 30新增了、支持、兼容Temporal API的假计时器,以及功能。如果被测代码使用Temporal API或时区逻辑,Jest 30的Temporal感知假计时器可避免一类脆弱的初始化问题。
--collect-testsjest.config.mtsclearMocksOnScope推荐用法:使用处理模块边界(使用实现部分mock)、包装真实方法、实现类型化mock、处理时间相关逻辑。详见的Jest章节。
jest.mock()jest.requireActualjest.spyOn()jest.Mocked<T>jest.useFakeTimers()references/patterns.mdVitest
Vitest
Same API as Jest, Vite-native. Stable: Vitest 4.1.x (June 2026); 5.0.0-beta is
out (beta.3, May 2026). Vitest 4 added (changed-files-only coverage),
/, and a stable browser mode. Vitest 5 beta removes the
option and requires Node 22 / Vite 6.4 — wait for stable before
adopting. Mock with /; the standout features are in-source testing
() and browser mode for component rendering. See
§ Vitest.
coverage.changedmockThrowmockThrowOncesequentialvi.mockvi.spyOnimport.meta.vitestreferences/patterns.mdAPI与Jest兼容,原生支持Vite。稳定版本为 Vitest 4.1.x(2026年6月);5.0.0-beta版本已发布(beta.3,2026年5月)。Vitest 4新增了(仅变更文件覆盖率)、/,以及稳定的浏览器模式。Vitest 5 beta 移除了选项,并要求 Node 22 / Vite 6.4——请等待稳定版本后再升级。使用/进行mock;其突出特性为源码内测试()和浏览器模式用于组件渲染。详见的Vitest章节。
coverage.changedmockThrowmockThrowOncesequentialvi.mockvi.spyOnimport.meta.vitestreferences/patterns.mdpytest
pytest
Use fixtures + (with for teardown),
for data-driven cases, and for env/attr substitution. Prefer fixtures
over / methods — fixtures compose and isolate per test. See
§ pytest.
conftest.pyyield@pytest.mark.parametrizemonkeypatchsetUptearDownreferences/patterns.md使用fixtures + (用实现清理)、实现数据驱动测试、替换环境变量/属性。优先使用fixtures而非/方法——fixtures具备组合性,且每个测试独立隔离。详见的pytest章节。
conftest.pyyield@pytest.mark.parametrizemonkeypatchsetUptearDownreferences/patterns.mdBun / Deno
Bun / Deno
bun testdeno test当运行环境为Bun或Deno时,(兼容Jest,无需额外配置)和(原生支持TS,带权限控制)是合理的默认选择。对于Node项目,优先使用Vitest/Jest以获得更丰富的插件生态。
bun testdeno testMocking Taxonomy
Mock分类
Pick the simplest double that does the job. Most of the time that is a stub.
| Double | What it does | When to use |
|---|---|---|
| Stub | Returns canned data, no verification | Control a dependency's return value |
| Spy | Wraps real impl, records calls | Verify calls without changing behavior |
| Mock | Replaces impl + records calls | Control return AND verify interaction |
| Fake | Simplified working impl (in-memory DB) | Complex stateful dependencies |
Rule of thumb: prefer stubs over mocks; reserve fakes for stateful dependencies;
never call a real external API in a unit test. Only mock the external boundary
(network, filesystem, DB, time) — let fast, deterministic internal collaborators run
for real, or you get a suite that is green while the integration is broken. The four
doubles in code: § Test doubles.
references/patterns.md选择满足需求的最简测试替身。大多数情况下,stub即可胜任。
| 测试替身 | 功能 | 适用场景 |
|---|---|---|
| Stub | 返回预设数据,不做调用验证 | 控制依赖的返回值 |
| Spy | 包装真实实现,记录调用情况 | 验证调用行为但不改变原有逻辑 |
| Mock | 替换原有实现并记录调用情况 | 既控制返回值又验证交互行为 |
| Fake | 简化的可用实现(如内存数据库) | 复杂的有状态依赖 |
经验法则: 优先使用stub而非mock;仅对有状态依赖使用fake;单元测试中绝不调用真实的外部API。仅mock外部边界(网络、文件系统、数据库、时间)——让快速、可预测的内部协作对象真实运行,否则测试套件会在集成逻辑损坏时仍显示通过。四种测试替身的代码示例:的测试替身章节。
references/patterns.mdCoverage
覆盖率配置
Configuration
配置方法
Jest — the threshold key is (singular). The plural
is not a Jest key: Jest ignores it silently, the gate never
enforces, and CI stays green at 30% coverage. This is the single most common config bug.
coverageThresholdcoverageThresholdsjavascript
// jest.config.js
module.exports = {
coverageProvider: "v8",
collectCoverageFrom: ["src/**/*.ts", "!src/**/*.{d,test,stories}.ts", "!src/**/index.ts"],
coverageThreshold: { global: { branches: 80, functions: 80, lines: 80, statements: 80 } },
};Vitest — set in with
(see § Vitest for the full block).
test.coverage.thresholdsvitest.config.tsprovider: "v8"references/patterns.mdpytest:
toml
undefinedJest——阈值配置项为****(单数形式)。复数形式并非Jest的有效配置项:Jest会静默忽略它,门禁永远不会生效,CI会在覆盖率仅30%时仍显示绿色。这是最常见的配置错误。
coverageThresholdcoverageThresholdsjavascript
// jest.config.js
module.exports = {
coverageProvider: "v8",
collectCoverageFrom: ["src/**/*.ts", "!src/**/*.{d,test,stories}.ts", "!src/**/index.ts"],
coverageThreshold: { global: { branches: 80, functions: 80, lines: 80, statements: 80 } },
};Vitest——在中设置,并指定(完整配置块请见的Vitest章节)。
vitest.config.tstest.coverage.thresholdsprovider: "v8"references/patterns.mdpytest:
toml
undefinedpyproject.toml
pyproject.toml
[tool.coverage.run]
source = ["src"]
omit = ["src//test_*.py", "src//conftest.py"]
[tool.coverage.report]
fail_under = 80
show_missing = true
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"]
undefined[tool.coverage.run]
source = ["src"]
omit = ["src//test_*.py", "src//conftest.py"]
[tool.coverage.report]
fail_under = 80
show_missing = true
exclude_lines = ["pragma: no cover", "if TYPE_CHECKING:"]
undefinedCoverage types and what to gate on
覆盖率类型与门禁优先级
| Type | Measures | Blind spots |
|---|---|---|
| Branch | Every if/else path taken? | Misses value combinations |
| Line | Each line executed? | Misses untested branches in one line |
| Statement | Each statement executed? | Similar to line |
| Function | Each function called? | Nothing about correctness |
Priority: Branch > Line > Statement > Function. Use 80% line as the baseline gate,
not a vanity target, and weight branch coverage higher. Focus coverage on business logic,
transformations, error paths, and edge cases; skip generated code, type definitions,
barrel exports, trivial getters, and framework boilerplate.
For interpreting which uncovered lines matter and doing gap analysis, that's, not this skill.coverage-analysis
| 类型 | 衡量指标 | 盲区 |
|---|---|---|
| 分支覆盖率 | 是否覆盖所有if/else路径? | 遗漏值组合场景 |
| 行覆盖率 | 是否执行每一行代码? | 遗漏单行内未测试的分支 |
| 语句覆盖率 | 是否执行每个语句? | 与行覆盖率类似 |
| 函数覆盖率 | 是否调用每个函数? | 无法验证逻辑正确性 |
优先级: 分支覆盖率 > 行覆盖率 > 语句覆盖率 > 函数覆盖率。使用80%行覆盖率作为基准门禁,而非虚荣指标,并优先关注分支覆盖率。重点覆盖业务逻辑、数据转换、错误路径和边界场景;跳过生成代码、类型定义、桶导出、简单getter和框架模板代码。
如需解读哪些未覆盖行有意义并进行缺口分析,请使用技能,而非本技能。coverage-analysis
CI gate
CI门禁
Jest and Vitest exit non-zero when thresholds fail — that exit code IS the gate. pytest
needs the flag explicitly:
yaml
- run: pytest --cov=src --cov-fail-under=80当未达到阈值时,Jest和Vitest会返回非零退出码——该退出码就是门禁。pytest需要显式添加参数:
yaml
- run: pytest --cov=src --cov-fail-under=80Mutation Testing
突变测试
Coverage tells you what code ran. Mutation testing tells you whether the tests would
catch a bug. It makes small source changes ( → , → ) and reruns
the suite against each mutant. If the suite still passes, the mutant survived — your
tests executed that logic but did not assert on it.
>>=truefalse覆盖率告诉你哪些代码被执行了。突变测试告诉你测试是否能发现bug。它会对源代码进行微小修改(如改为,改为),并针对每个变异体重新运行测试套件。如果测试套件仍通过,说明该变异体存活——你的测试执行了这段逻辑,但未对其进行断言验证。
>>=truefalseStryker (JS/TS)
Stryker(JS/TS)
bash
npm i -D @stryker-mutator/core @stryker-mutator/jest-runner # or vitest-runnerjavascript
// stryker.config.json (Stryker's documented default; .mjs/.mts also load)
{
"testRunner": "jest",
"coverageAnalysis": "perTest",
"mutate": ["src/**/*.ts", "!src/**/*.test.ts"],
"thresholds": { "high": 80, "low": 60, "break": 50 },
"reporters": ["html", "clear-text", "progress"]
}Stryker's own defaults are — means
no failing exit. Set (e.g. 50) to make a low score fail CI. Run: .
{ high: 80, low: 60, break: null }break: nullbreaknpx stryker runbash
npm i -D @stryker-mutator/core @stryker-mutator/jest-runner # 或 vitest-runnerjavascript
// stryker.config.json (Stryker官方默认配置;也支持.mjs/.mts格式)
{
"testRunner": "jest",
"coverageAnalysis": "perTest",
"mutate": ["src/**/*.ts", "!src/**/*.test.ts"],
"thresholds": { "high": 80, "low": 60, "break": 50 },
"reporters": ["html", "clear-text", "progress"]
}Stryker的默认阈值为——意味着低分不会导致CI失败。设置(如50)可让低分触发CI失败。运行命令:。
{ high: 80, low: 60, break: null }break: nullbreaknpx stryker runmutmut (Python) — mutmut 3.x
mutmut(Python)——mutmut 3.x
mutmut 3 dropped the old CLI surface. Configure paths in a block, run, then
review survivors in the TUI:
[mutmut]ini
undefinedmutmut 3重构了旧版CLI界面。在块中配置路径,运行后在TUI中查看存活变异体:
[mutmut]ini
undefinedsetup.cfg (or a [tool.mutmut] table in pyproject.toml)
setup.cfg (或在pyproject.toml中添加[tool.mutmut]配置块)
[mutmut]
paths_to_mutate=src/
```bash
pip install mutmut # 3.5.x
mutmut run # paths come from config, not a flag
mutmut browse # interactive TUI: inspect and retest survivors
mutmut apply <mutant_id> # write a survivor to disk to see what it changedAvoid:,mutmut run --paths-to-mutate=src/, andmutmut results— that was the mutmut <3 surface. Themutmut show 42flag is gone (paths move to the--paths-to-mutateconfig block) and[mutmut]/resultsare replaced byshow/browse(mutmut 3.5.x, verified June 2026). Following the old commands errors out on a current install.apply
[mutmut]
paths_to_mutate=src/
```bash
pip install mutmut # 3.5.x版本
mutmut run # 路径来自配置,无需命令行参数
mutmut browse # 交互式TUI:查看并重新测试存活变异体
mutmut apply <mutant_id> # 将存活变异体写入磁盘,查看具体修改内容注意: 避免使用、mutmut run --paths-to-mutate=src/和mutmut results——这些是mutmut 3.x之前的用法。mutmut show 42参数已移除(路径需移至--paths-to-mutate配置块),[mutmut]/results被show/browse替代(mutmut 3.5.x,2026年6月验证)。在当前版本中使用旧命令会报错。apply
Interpreting scores
分数解读
| Score | Meaning |
|---|---|
| 90%+ | Strong — catching most logic changes |
| 70–89% | Decent — review survivors in critical paths |
| <70% | Tests execute code but do not verify behavior |
Run mutation testing on critical business logic, not the whole codebase (it is slow).
Ignore equivalent mutants — logically identical code where no test could ever tell the difference.
| 分数 | 含义 |
|---|---|
| 90%+ | 优秀——能捕获大多数逻辑变更 |
| 70–89% | 良好——需重点检查核心路径的存活变异体 |
| <70% | 测试仅执行代码,但未验证逻辑正确性 |
仅对核心业务逻辑运行突变测试,而非整个代码库(速度较慢)。忽略等效变异体——即逻辑上完全相同、测试永远无法区分的代码修改。
Snapshot Testing
快照测试
Use for: UI component render output, serialized data structures, CLI formatting —
output where exact structure matters and is tedious to assert field-by-field.
Do not use for: frequently changing output (snapshot fatigue → rubber-stamp reviews),
large snapshots (unreviewable), implementation details (CSS classes, internal IDs), or as
a substitute for a targeted assertion when one specific value is what matters.
Prefer inline snapshots for small output (<20 lines) and property matchers
() for dynamic fields like ids and timestamps. Always run CI with
so an unknown snapshot fails instead of being silently written and committed.
Code: § Snapshot testing.
expect.any(String)--cireferences/patterns.md适用场景: UI组件渲染输出、序列化数据结构、CLI格式化输出——这些场景下输出的精确结构很重要,且逐字段断言过于繁琐。
不适用场景: 频繁变更的输出(快照疲劳导致草率审核)、大型快照(难以审核)、实现细节(CSS类名、内部ID),或当只需断言某个特定值时替代精准断言。
对于小型输出(少于20行)优先使用内联快照,对于动态字段(如ID、时间戳)使用属性匹配器()。CI运行时务必添加参数,这样未知快照会导致失败而非被静默写入并提交。代码示例:的快照测试章节。
expect.any(String)--cireferences/patterns.mdAnti-Patterns
反模式
Testing private methods — Test through the public API. If a private method really
needs its own tests, extract it to its own module with a public surface.
Mocking everything — Only mock external boundaries (network, filesystem, DB, time).
A suite where every collaborator is mocked passes while the wiring between them is broken.
The plural — Jest ignores it; the gate never fires; CI is green
at any coverage. The key is (singular). See Coverage above.
coverageThresholdscoverageThresholdFaking all timers blindly — / with no
allowlist can deadlock code awaiting a real microtask. Fake only what the test needs
( / ). See § Jest timers.
jest.useFakeTimers()vi.useFakeTimers()doNotFaketoFakereferences/patterns.mdAsync test without — a forgotten makes the assertion never run and
the test passes vacuously. Add / to async
tests so a missing assertion fails them.
awaitawaitexpect.assertions(n)expect.hasAssertions()Snapshot overuse — Use for a specific value; reserve
snapshots for structured output you can't assert field-by-field.
expect(x).toBe("active")Non-descriptive names — Replace with .
"works""should return empty array when no items match the filter"Shared mutable state — Initialize in , not at module scope:
beforeEachtypescript
// Bad: shared mutation // Good: fresh per test
const items = []; let items: string[];
it("A", () => items.push("a")); beforeEach(() => { items = []; });
it("B", () => { it("A", () => { items.push("a"); expect(items).toHaveLength(1); });
items.push("b"); it("B", () => { items.push("b"); expect(items).toHaveLength(1); });
expect(items).toHaveLength(1); // FAILS
});测试私有方法——通过公共API进行测试。如果私有方法确实需要单独测试,将其提取为独立模块并暴露公共接口。
Mock所有对象——仅mock外部边界(网络、文件系统、数据库、时间)。如果测试套件将所有协作对象都mock掉,即使它们之间的连接逻辑损坏,测试仍会通过。
使用复数形式——Jest会忽略该配置,门禁永远不会生效,CI在任何覆盖率下都会显示绿色。正确的配置项是(单数形式)。详见上文覆盖率配置部分。
coverageThresholdscoverageThreshold盲目伪造所有计时器——不带白名单的/可能导致等待真实微任务的代码死锁。仅伪造测试所需的计时器(使用/配置)。详见的Jest计时器章节。
jest.useFakeTimers()vi.useFakeTimers()doNotFaketoFakereferences/patterns.md异步测试未添加——遗漏会导致断言永远不会执行,测试无意义地通过。在异步测试中添加/,确保遗漏断言时测试失败。
awaitawaitexpect.assertions(n)expect.hasAssertions()过度使用快照——对于特定值,使用这类精准断言;仅在无法逐字段断言结构化输出时使用快照。
expect(x).toBe("active")测试名称无描述性——将替换为这类明确名称。
"works""当没有匹配项时应返回空数组"共享可变状态——在中初始化状态,而非模块作用域:
beforeEachtypescript
// 不良示例:共享可变状态 // 良好示例:每个测试使用全新状态
const items = []; let items: string[];
it("A", () => items.push("a")); beforeEach(() => { items = []; });
it("B", () => { it("A", () => { items.push("a"); expect(items).toHaveLength(1); });
items.push("b"); it("B", () => { items.push("b"); expect(items).toHaveLength(1); });
expect(items).toHaveLength(1); // 测试失败
});Verification
验证步骤
Prove the suite runs and the gate actually fails on under-coverage — the exact thing the
typo silently disables.
coverageThreshold- Tests run and pass: (or
npx jest,vitest run) exitspytest -q.0 - The gate bites. Run coverage and confirm a non-zero exit when below threshold:
Temporarily set a threshold above current coverage (e.g. 99) and confirm the command fails. If it exitsbash
npx jest --coverage --ci # Jest/Vitest exit !=0 below coverageThreshold vitest run --coverage # same for Vitest pytest --cov=src --cov-fail-under=80 # pytest exits !=0 below the floor, your threshold key is wrong (likely the plural0).coverageThresholds - Snapshots are safe in CI: the run uses , so an unknown snapshot fails rather than being written.
--cishows no newgit statusafter a CI-mode run.*.snap
验证测试套件能正常运行,且门禁在覆盖率不足时确实会触发——这正是拼写错误会静默失效的场景。
coverageThreshold- 测试正常运行并通过: (或
npx jest、vitest run)返回pytest -q。0 - 门禁生效。 运行覆盖率检查,确认未达到阈值时返回非零退出码:
临时将阈值设置为高于当前覆盖率(如99),确认命令会失败。如果仍返回bash
npx jest --coverage --ci # Jest/Vitest在未达到coverageThreshold时返回非零值 vitest run --coverage # Vitest同理 pytest --cov=src --cov-fail-under=80 # pytest在低于阈值时返回非零值,说明你的阈值配置项有误(大概率是使用了复数形式0)。coverageThresholds - CI中快照安全: 运行时使用参数,这样未知快照会导致失败而非被自动写入。CI模式运行后,
--ci应显示无新的git status文件。*.snap
Done When
完成标准
- Coverage thresholds configured in (key
jest.config.*, singular),coverageThreshold(vitest.config.*), orcoverage.thresholds(pyproject.toml) AND verified to exit non-zero below threshold (Verification step 2)fail_under - Test files all live in the project's single chosen location (co-located OR /
__tests__) —tests/shows no ad-hoc test pathsgit ls-files - External boundaries (HTTP, DB, time) are mocked and internal collaborators are not — finds no real network/DB clients constructed in test files
grep - No test reaches outside the process boundary — suite passes with the network disabled and no test DB running
- CI runs the test command with (Jest/Vitest) so an unknown snapshot fails the build instead of being auto-written
--ci
- 已在(配置项为
jest.config.*,单数)、coverageThreshold(vitest.config.*)或coverage.thresholds(pyproject.toml)中配置覆盖率阈值,并验证未达到阈值时会返回非零退出码(验证步骤2)fail_under - 所有测试文件均存于项目选定的单一位置(与源码同目录或/
__tests__目录)——tests/显示无临时测试路径git ls-files - 外部边界(HTTP、数据库、时间)已被mock,内部协作对象未被mock——未在测试文件中找到真实网络/数据库客户端的实例化代码
grep - 测试未超出进程边界——禁用网络且无测试数据库运行时,测试套件仍能通过
- CI运行测试命令时添加了参数(Jest/Vitest),这样未知快照会导致构建失败而非被自动写入
--ci
Reference Files (in references/
)
references/参考文件(位于references/
目录)
references/- patterns.md — full runnable examples per framework: Jest setup/teardown, module/spy/timer mocks, async guards; Vitest config, in-source tests, concurrency, browser mode; pytest fixtures/parametrize/monkeypatch; Bun/Deno; the four test doubles; snapshot file/inline/property matchers.
- patterns.md——各框架的完整可运行示例:Jest初始化/清理、模块/spy/计时器mock、异步防护;Vitest配置、源码内测试、并发、浏览器模式;pytest fixtures/参数化/monkeypatch;Bun/Deno;四种测试替身;快照文件/内联/属性匹配器。
Related Skills
相关技能
- coverage-analysis — interpreting coverage reports, finding meaningful gaps, mutation score as a first-class signal. Go there to read coverage; stay here to configure and gate it.
- ci-cd-integration — test stages in pipelines, parallelization, caching, deployment gating.
- ai-test-generation — when an AI writes the test code from a spec/PRD; this skill is for writing and structuring tests by hand.
- ai-qa-review — auditing existing tests for hallucinated APIs, fabricated imports, and closed-loop tests.
- shift-left-testing — pre-commit hooks, IDE integration, and TDD workflow around these tests.
- coverage-analysis——解读覆盖率报告、查找有意义的覆盖缺口、将突变分数作为核心指标。如需分析覆盖率,请使用该技能;本技能专注于覆盖率配置与门禁设置。
- ci-cd-integration——流水线中的测试阶段、并行化、缓存、部署门禁。
- ai-test-generation——由AI根据需求文档/PRD生成测试代码;本技能专注于手动编写和结构化测试。
- ai-qa-review——审核现有测试中的API幻觉、伪造导入和闭环测试问题。
- shift-left-testing——围绕这些测试的预提交钩子、IDE集成和TDD工作流。