写测试是提升代码质量最有效的方式,但也是最耗时的工作之一。 Claude Code 能从函数签名推断边界条件、生成完整的测试套件, 让测试覆盖率从 0 到 80% 变得简单很多。
核心 Prompt 策略
策略 1:提供实现,要求覆盖所有分支
Write comprehensive unit tests for this function:
```python
def calculate_discount(price: float, user_type: str, coupon: str | None = None) -> float:
if price <= 0:
raise ValueError("Price must be positive")
discount = 0.0
if user_type == "premium":
discount = 0.2
elif user_type == "regular":
discount = 0.1
if coupon == "EXTRA10":
discount += 0.1
elif coupon == "HALF":
discount = 0.5
return price * (1 - min(discount, 1.0))
Test requirements:
- Happy path for each user_type
- All coupon combinations
- Edge cases: price=0, negative price, unknown user_type
- Boundary: discount capped at 100% (coupon=HALF + premium)
- Type: use pytest + parametrize for similar cases
Use pytest, no external dependencies.
### 策略 2:Table-Driven 测试(适合多输入场景)
Write table-driven tests for the validate_email function. Use pytest.mark.parametrize.
Cover:
- Valid emails (standard, subdomain, plus addressing)
- Invalid: missing @, missing domain, double @, spaces
- Edge cases: empty string, very long email (>254 chars)
- Unicode: Chinese characters in local part
Format: @pytest.mark.parametrize("email,expected", [ ("valid@example.com", True), ... ]) def test_validate_email(email, expected): assert validate_email(email) == expected
### 策略 3:从行为描述生成测试(TDD 方式)
I'm going to implement a ShoppingCart class. Write tests FIRST based on this spec, before I write the code:
Spec:
- Cart starts empty
- add_item(product_id, quantity) adds items
- Adding same product increases quantity
- remove_item(product_id) removes item
- get_total() returns sum of (price * quantity) for all items
- apply_coupon("SAVE10") applies 10% discount to total
- Cart cannot have negative quantities
- Empty cart total is 0
Generate pytest tests that fully specify this behavior. I'll write the implementation to make them pass.
## 单元测试:Mock 依赖
Write unit tests for UserService.create_user() method.
The method:
- Validates email uniqueness (calls UserRepository.find_by_email)
- Hashes password (calls hash_password utility)
- Saves user (calls UserRepository.save)
- Sends welcome email (calls EmailService.send_welcome)
- Returns created user
Mock all external dependencies. Test cases:
- Happy path: user created successfully
- Email already exists: raises DuplicateEmailError
- Repository save fails: raises exception, email NOT sent
- Email send fails: user IS saved (email failure is non-critical)
Use pytest + unittest.mock (no pytest-mock). Show how to verify mock call arguments.
## 集成测试:数据库 Fixtures
Write pytest integration tests for OrderRepository.
Database: PostgreSQL (use pytest-asyncio + asyncpg for async)
Fixtures needed:
- test_db: create test database, run migrations, yield connection, cleanup
- clean_db: truncate all tables between tests (faster than recreate)
- sample_user: create a test user in DB
- sample_products: create 3 test products
Test cases:
- create_order() inserts order + order_items correctly
- get_order_by_id() returns full order with items
- list_user_orders() returns correct pagination
- update_order_status() updates and records history
- concurrent creates don't deadlock
Use factory functions for test data, not hardcoded values.
## E2E 测试:Playwright
Write Playwright E2E tests for the checkout flow.
Flow: Login → Add to Cart → Checkout → Payment → Confirmation
Test file: tests/e2e/checkout.spec.ts
Setup:
- Use Playwright with TypeScript
- Base URL from environment variable
- Use page fixtures with authenticated state (avoid login in every test)
Test cases:
- Complete checkout with valid card
- Form validation errors (empty fields)
- Payment failure (use Stripe test card 4000000000000002)
- Cart persists after page refresh
- Mobile viewport (375px) checkout works
Add custom page objects for:
- CartPage (add item, view total)
- CheckoutPage (fill form, submit)
- ConfirmationPage (verify order number)
Include retry logic for flaky elements (waitForSelector with timeout).
## 提升覆盖率:分析未覆盖路径
Analyze the test coverage report and generate missing tests.
Current coverage: 67%
Uncovered lines from coverage report:
- src/payment/processor.py lines 45-52 (refund edge case)
- src/auth/middleware.py lines 88-95 (expired token path)
- src/orders/service.py lines 120-135 (concurrent order creation)
For each uncovered section:
- Explain what scenario triggers this code path
- Write the minimum test to cover it
- Suggest if the code itself might have a bug
Coverage tool output: [粘贴 coverage report]
## TDD 工作流(测试先行)
```bash
# 推荐的 Claude Code TDD 工作流
# Step 1: 描述需求,让 Claude 写测试
"Write tests for a rate limiter class that:
- Allows N requests per minute per user
- Returns True if allowed, False if blocked
- Resets counter after 60 seconds"
# Step 2: 运行测试(会失败,因为还没实现)
pytest tests/test_rate_limiter.py
# 确认测试是 FAIL 而不是 ERROR(测试本身没有语法错误)
# Step 3: 让 Claude 实现代码
"Now implement RateLimiter to make these tests pass"
# Step 4: 运行测试确认通过
pytest tests/test_rate_limiter.py -v
# Step 5: 让 Claude 重构(测试保证不破坏功能)
"Refactor RateLimiter to use Redis instead of in-memory dict.
All tests must still pass."
CLAUDE.md 测试规范
## 测试规范
### 覆盖率目标
- 新代码:>85%
- 整体项目:>75%
- 核心业务逻辑:>95%
### 测试框架
- Python: pytest + pytest-asyncio
- TypeScript: Vitest + @testing-library
- E2E: Playwright
### 命名规范
- 测试函数:test_动词_场景_期望结果
例:test_create_order_with_invalid_stock_raises_error
- 测试文件:与被测文件同名加 test_ 前缀
### 必须测试的内容
- 所有公共 API 方法
- 所有 if/else 分支
- 所有异常处理路径
- 边界值(0, -1, null, 空字符串, 超长输入)来源:Anthropic 官方文档 + 测试工程最佳实践