1.6 KiB
1.6 KiB
好的测试与糟糕的测试
好的测试
集成风格:通过真实接口进行测试,而非模拟内部组件。
// 好:测试可观察的行为
test("用户可以使用有效购物车完成结账", async () => {
const cart = createCart();
cart.add(product);
const result = await checkout(cart, paymentMethod);
expect(result.status).toBe("confirmed");
});
特征:
- 测试用户/调用者关心的行为
- 仅使用公开 API
- 能够经受内部重构
- 描述「做什么」,而非「怎么做」
- 每个测试只有一个逻辑断言
糟糕的测试
实现细节测试:与内部结构耦合。
// 差:测试实现细节
test("结账时调用 paymentService.process", async () => {
const mockPayment = jest.mock(paymentService);
await checkout(cart, payment);
expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
});
危险信号:
- 模拟内部协作对象
- 测试私有方法
- 对调用次数/顺序进行断言
- 重构(未改变行为)时测试破裂
- 测试名称描述「怎么做」而非「做什么」
- 通过外部手段而非接口进行验证
// 差:绕过接口进行验证
test("createUser 保存到数据库", async () => {
await createUser({ name: "Alice" });
const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
expect(row).toBeDefined();
});
// 好:通过接口进行验证
test("createUser 使用户可被检索到", async () => {
const user = await createUser({ name: "Alice" });
const retrieved = await getUser(user.id);
expect(retrieved.name).toBe("Alice");
});