testing-guidelines
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTesting Guidelines
测试指南
Follow these principles when writing tests for this codebase.
在为本代码库编写测试时,请遵循以下原则。
Core Principles
核心原则
1. Mock External Services, Use Real Fixtures
1. 模拟外部服务,使用真实Fixtures
ALWAYS mock third-party network services. ALWAYS use fixtures based on real-world data.
- Fixtures must be scrubbed of PII (use dummy data like ,
foo@example.com)user-123 - Capture real API responses, then sanitize them
- Never make actual network calls in tests
务必模拟第三方网络服务。务必使用基于真实数据的Fixtures。
- Fixtures必须清除PII信息(使用虚拟数据,如、
foo@example.com)user-123 - 捕获真实API响应,然后进行清理
- 测试中绝不要发起实际的网络请求
2. Prefer Integration Tests Over Unit Tests
2. 优先选择Integration Tests而非Unit Tests
Focus on end-to-end style tests that validate inputs and outputs, not implementation details.
- Test the public interface, not internal methods
- Unit tests are valuable for edge cases in pure functions, but integration tests are the priority
- If refactoring breaks tests but behavior is unchanged, the tests were too coupled to implementation
专注于端到端风格的测试,验证输入和输出,而非实现细节。
- 测试公共接口,而非内部方法
- Unit Tests对纯函数的边缘情况很有价值,但Integration Tests是优先项
- 如果重构导致测试失败但行为未改变,说明测试与实现耦合过紧
3. Minimize Edge Case Testing
3. 减少边缘情况测试
Don't test every variant of a problem.
- Cover the common path thoroughly
- Skip exhaustive input permutations
- Skip unlikely edge cases that add maintenance burden without value
- One representative test per category of input is usually sufficient
无需测试问题的所有变体。
- 全面覆盖常规路径
- 跳过详尽的输入排列组合
- 跳过那些会增加维护负担却无实际价值的罕见边缘情况
- 通常每个输入类别只需一个代表性测试即可
4. Always Add Regression Tests for Bugs
4. 始终为漏洞添加回归测试
When a bug is identified, ALWAYS add a test that would have caught it.
- The test should fail before the fix and pass after
- Name it descriptively to document the bug
- This prevents the same bug from recurring
Note: Regression tests are for unintentional broken behavior (bugs), not intentional changes. Intentional feature removals, deprecations, or breaking changes do NOT need regression tests—these are design decisions, not defects.
当发现漏洞时,务必添加一个本可以发现该漏洞的测试。
- 该测试在修复前应失败,修复后应通过
- 给测试起一个描述性的名称,以记录该漏洞
- 这可以防止同一漏洞再次出现
注意: 回归测试适用于非故意的功能损坏(漏洞),而非有意的变更。有意的功能移除、弃用或破坏性变更不需要回归测试——这些是设计决策,而非缺陷。
5. Cover Every User Entry Point
5. 覆盖所有用户入口点
ALWAYS have at least one basic test for each customer/user entry point.
- CLI commands, API endpoints, public/exported functions
- Test the common/happy path first
- This proves the entry point works at all
Note: "Entry point" means the public interface—exported functions, CLI commands, API routes. Internal/private functions are NOT entry points, even if they handle user-facing flags or options. Test entry points; internal functions get coverage through those tests.
务必为每个客户/用户入口点至少编写一个基础测试。
- CLI命令、API端点、公共/导出函数
- 首先测试常规/顺畅路径
- 这可以证明入口点能够正常工作
注意: “入口点”指的是公共接口——导出的函数、CLI命令、API路由。内部/私有函数不属于入口点,即使它们处理面向用户的标志或选项。测试入口点即可;内部函数的测试覆盖会通过这些入口点的测试实现。
6. Tests Validate Before Manual QA
6. 测试在手动QA前完成验证
Tests are how we validate ANY functionality works before manual testing.
- Write tests first or alongside code, not as an afterthought
- If you can't test it, reconsider the design
- Passing tests should give confidence to ship
测试是我们在手动测试前验证任何功能是否正常工作的方式。
- 先编写测试,或与代码同步编写,而非事后补写
- 如果无法测试某个功能,请重新考虑其设计
- 通过的测试应能让我们有信心发布功能
Technical Guidelines
技术指南
File Organization
文件组织
- Test files use extension
*.test.ts - Co-locate tests with source: →
foo.tsfoo.test.ts
- 测试文件使用扩展名
*.test.ts - 测试文件与源代码放在同一目录下:→
foo.tsfoo.test.ts
Test Isolation
测试隔离
Every test must:
- Run independently without affecting other tests
- Use temporary directories for file operations
- Clean up resources in hooks
afterEach
typescript
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
describe('my feature', () => {
let tempDir: string;
beforeEach(() => {
tempDir = join(tmpdir(), `warden-test-${Date.now()}`);
mkdirSync(tempDir, { recursive: true });
});
afterEach(() => {
rmSync(tempDir, { recursive: true, force: true });
});
it('does something with files', () => {
writeFileSync(join(tempDir, 'test.ts'), 'content');
// ... test code
});
});每个测试必须:
- 独立运行,不影响其他测试
- 使用临时目录进行文件操作
- 在钩子中清理资源
afterEach
typescript
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
describe('my feature', () => {
let tempDir: string;
beforeEach(() => {
tempDir = join(tmpdir(), `warden-test-${Date.now()}`);
mkdirSync(tempDir, { recursive: true });
});
afterEach(() => {
rmSync(tempDir, { recursive: true, force: true });
});
it('does something with files', () => {
writeFileSync(join(tempDir, 'test.ts'), 'content');
// ... test code
});
});Pure Function Tests
纯函数测试
For pure functions without side effects, no special setup is needed:
typescript
import { describe, it, expect } from 'vitest';
import { matchGlob } from './matcher.js';
describe('matchGlob', () => {
it('matches exact paths', () => {
expect(matchGlob('src/index.ts', 'src/index.ts')).toBe(true);
});
});对于无副作用的纯函数,无需特殊设置:
typescript
import { describe, it, expect } from 'vitest';
import { matchGlob } from './matcher.js';
describe('matchGlob', () => {
it('matches exact paths', () => {
expect(matchGlob('src/index.ts', 'src/index.ts')).toBe(true);
});
});Running Tests
运行测试
bash
pnpm test # Run all tests in watch mode
pnpm test:run # Run all tests oncebash
pnpm test # 以监听模式运行所有测试
pnpm test:run # 运行所有测试一次Checklist Before Submitting
提交前检查清单
- New entry points have at least one happy-path test
- Bug fixes (not intentional changes) include a regression test
- External services are mocked with sanitized fixtures
- Tests validate behavior, not implementation
- No shared state between tests
- 新入口点至少有一个顺畅路径测试
- 漏洞修复(非有意变更)包含回归测试
- 外部服务已使用清理后的Fixtures模拟
- 测试验证的是行为,而非实现
- 测试之间无共享状态