Loading...
Loading...
Compare original and translation side by side
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRSTNO PRODUCTION CODE WITHOUT A FAILING TEST FIRSTClear name, tests real behavior, one thing
</Good>
<Bad>
```typescript
test('retry works', async () => {
const mock = jest.fn()
.mockRejectedValueOnce(new Error())
.mockRejectedValueOnce(new Error())
.mockResolvedValueOnce('success');
await retryOperation(mock);
expect(mock).toHaveBeenCalledTimes(3);
});名称清晰,测试真实行为,仅测试一项功能
</Good>
<Bad>
```typescript
test('retry works', async () => {
const mock = jest.fn()
.mockRejectedValueOnce(new Error())
.mockRejectedValueOnce(new Error())
.mockResolvedValueOnce('success');
await retryOperation(mock);
expect(mock).toHaveBeenCalledTimes(3);
});npm test path/to/test.test.tsnpm test path/to/test.test.tsnpm test path/to/test.test.tsnpm test path/to/test.test.ts| Quality | Good | Bad |
|---|---|---|
| Minimal | One thing. "and" in name? Split it. | |
| Clear | Name describes behavior | |
| Shows intent | Demonstrates desired API | Obscures what code should do |
| 质量维度 | 良好实践 | 不良实践 |
|---|---|---|
| 最小化 | 仅测试一项功能。名称里有“和”?拆分测试。 | |
| 清晰性 | 名称描述行为 | |
| 体现意图 | 展示期望的API用法 | 模糊代码应实现的功能 |
| Excuse | Reality |
|---|---|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
| "I'll test after" | Tests passing immediately prove nothing. |
| "Tests after achieve same goals" | Tests-after = "what does this do?" Tests-first = "what should this do?" |
| "Already manually tested" | Ad-hoc does not equal systematic. No record, can't re-run. |
| "Deleting X hours is wasteful" | Sunk cost fallacy. Keeping unverified code is technical debt. |
| "Keep as reference, write tests first" | You'll adapt it. That's testing after. Delete means delete. |
| "Need to explore first" | Fine. Throw away exploration, start with TDD. |
| "Test hard = design unclear" | Listen to test. Hard to test = hard to use. |
| "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. |
| "Manual test faster" | Manual doesn't prove edge cases. You'll re-test every change. |
| "Existing code has no tests" | You're improving it. Add tests for existing code. |
| 借口 | 现实 |
|---|---|
| “太简单了不用测试” | 简单代码也会出错。测试只需30秒。 |
| “我之后再写测试” | 立即通过的测试无法证明任何事。 |
| “之后写测试能达到同样目标” | 后写测试=“代码做了什么?” 先写测试=“代码应该做什么?” |
| “已经手动测试过了” | 临时测试不等于系统化测试。没有记录,无法重新运行。 |
| “删除X小时的工作很浪费” | 沉没成本谬误。保留未验证的代码是技术债务。 |
| “留作参考,先写测试” | 你会参考它修改代码。这本质还是后写测试。删除就是彻底删除。 |
| “需要先探索一下” | 没问题。探索后丢弃代码,用TDD重新开始。 |
| “测试难度高=设计不清晰” | 倾听测试的反馈。难测试=难使用。 |
| “TDD会拖慢进度” | TDD比调试更快。务实就是先写测试。 |
| “手动测试更快” | 手动测试无法证明覆盖所有边缘情况。每次代码变更你都要重新测试。 |
| “现有代码没有测试” | 你正在改进它。为现有代码添加测试。 |
test('rejects empty email', async () => {
const result = await submitForm({ email: '' });
expect(result.error).toBe('Email required');
});$ npm test
FAIL: expected 'Email required', got undefinedfunction submitForm(data: FormData) {
if (!data.email?.trim()) {
return { error: 'Email required' };
}
// ...
}$ npm test
PASStest('rejects empty email', async () => {
const result = await submitForm({ email: '' });
expect(result.error).toBe('Email required');
});$ npm test
FAIL: expected 'Email required', got undefinedfunction submitForm(data: FormData) {
if (!data.email?.trim()) {
return { error: 'Email required' };
}
// ...
}$ npm test
PASSpnpm lint:fixpnpm formatpnpm lint:fixpnpm formatpnpm lint:fixpnpm formatpnpm lint:fixpnpm format| Problem | Solution |
|---|---|
| Don't know how to test | Write wished-for API. Write assertion first. Ask your human partner. |
| Test too complicated | Design too complicated. Simplify interface. |
| Must mock everything | Code too coupled. Use dependency injection. |
| Test setup huge | Extract helpers. Still complex? Simplify design. |
| 问题 | 解决方案 |
|---|---|
| 不知道如何测试 | 编写期望的API。先写断言。咨询你的人类合作者。 |
| 测试过于复杂 | 设计过于复杂。简化接口。 |
| 必须Mock所有依赖 | 代码耦合度太高。使用依赖注入。 |
| 测试准备工作繁重 | 提取辅助函数。仍然复杂?简化设计。 |
Production code -> test exists and failed first
Otherwise -> not TDDProduction code -> test exists and failed first
Otherwise -> not TDDtesting-experttesting-expert| Framework | Purpose | Usage |
|---|---|---|
| Jasmine + Karma | Unit testing components and services | Default Angular test runner |
| Angular Testing Utilities | Component testing with focus on user behavior | DOM interaction testing |
| Protractor / Cypress | End-to-end testing of user flows | Full integration tests |
| 框架 | 用途 | 使用场景 |
|---|---|---|
| Jasmine + Karma | 组件和服务的单元测试 | Angular默认测试运行器 |
| Angular Testing Utilities | 聚焦用户行为的组件测试 | DOM交互测试 |
| Protractor / Cypress | 用户流程的端到端测试 | 全集成测试 |
| Test Type | When to Use | Tools |
|---|---|---|
| Unit Tests | Isolated component/function logic | Jest, Vitest, pytest |
| Integration Tests | Multiple components working together | Testing Library, pytest |
| E2E Tests | Full user flows through the application | Cypress, Playwright |
| API Tests | Endpoint validation | Supertest, httpx |
| 测试类型 | 使用场景 | 工具 |
|---|---|---|
| 单元测试 | 孤立的组件/函数逻辑测试 | Jest, Vitest, pytest |
| 集成测试 | 多个组件协作的测试 | Testing Library, pytest |
| 端到端测试 | 应用全用户流程测试 | Cypress, Playwright |
| API测试 | 端点验证 | Supertest, httpx |
test-generatorcomprehensive-unit-testing-with-pytestqa-workflowtest-generatorcomprehensive-unit-testing-with-pytestqa-workflow.claude/context/memory/learnings.md.claude/context/memory/learnings.md.claude/context/memory/issues.md.claude/context/memory/decisions.mdASSUME INTERRUPTION: If it's not in memory, it didn't happen.
.claude/context/memory/learnings.md.claude/context/memory/learnings.md.claude/context/memory/issues.md.claude/context/memory/decisions.md假设会被中断:如果没记录在记忆中,就等于没发生。