testing-guidelines

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Testing 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
    *.test.ts
    extension
  • Co-locate tests with source:
    foo.ts
    foo.test.ts
  • 测试文件使用
    *.test.ts
    扩展名
  • 测试文件与源代码放在同一目录下:
    foo.ts
    foo.test.ts

Test Isolation

测试隔离

Every test must:
  • Run independently without affecting other tests
  • Use temporary directories for file operations
  • Clean up resources in
    afterEach
    hooks
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 once
bash
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模拟
  • 测试验证的是行为,而非实现
  • 测试之间无共享状态