Testing Best Practice 是一个面向测试编写、审查与重构的技能,其核心目标是让测试更贴近需求、更稳定、更易维护。它基于 Artem 风格的测试原则,强调测试意图而非实现细节。
用途
当用户需要编写新测试、改进现有测试或定义测试标准时,该技能提供一套可遵循的规则。它帮助开发者避免常见的测试脆弱性问题,例如过度依赖内部实现、模拟内部函数、断言私有状态或精确调用顺序等。
主要能力
该技能涵盖以下核心原则:
- 测试意图,而非实现:让测试读起来像需求,断言可观察行为(返回值、DOM、副作用、公共契约),避免断言私有状态、内部变量或精确调用序列,除非行为本身要求如此。
- 偏好高信号、低维护的测试:测试应仅在行为契约变化时失败;使用最小、最清晰的输入来演示行为;用真实世界语言命名测试,例如
it("allows a customer to update their email", async () => {})。 - 严格控制非确定性以避免脆弱性:控制时间(假定时器)、随机性和外部系统;单元/集成测试中不访问真实网络、数据库或文件系统;显式等待所有异步行为,避免未跟踪的 Promise。
- 模拟边界,而非内部:通过 Mock Service Worker (MSW) 或等效工具模拟 HTTP;不要模拟自己的内部函数,而应模拟外部边界;模拟时需覆盖成功和失败模式(错误、无效数据、超时)。
- 优先集成测试:纯函数和复杂分支使用单元测试;跨多层行为使用集成测试;端到端测试保持少量并聚焦关键用户流程。
- 为可测试性重构:如果测试难以编写,考虑修改生产代码——提取纯函数、注入依赖而非使用全局变量、将副作用隔离在小型、定义良好的边界之后。
- 使用 using 关键字进行资源清理:对可释放资源(临时文件/目录、数据库连接或事务、事件监听器、假定时器或暴露 Symbol.dispose 的自定义资源)使用 using,优先于手动 afterEach 清理。
使用方式
该技能以指令形式提供,当用户请求测试相关帮助时,技能会按照上述规则生成或重构测试。它提供了推荐的测试布局结构:
describe("FeatureName", () => {
it("states the requirement", async () => {
// Arrange
const user = buildUser();
// Act
const result = await updateEmail(user.id, "new@x.com");
// Assert
expect(result.email).toBe("new@x.com");
});
});
技能还包含示例,展示如何生成测试和重构脆弱测试。例如,对于调用 HTTP API 的 updateEmail(userId, email) 函数,技能建议使用 MSW 模拟 HTTP 边界,断言返回结果和可观察副作用,避免监视内部辅助函数如 apiClient.get。
适用场景
该技能适用于以下场景:
- 编写新测试时,需要遵循最佳实践。
- 改进现有测试,使其更稳定、更易维护。
- 定义团队测试标准。
- 重构脆弱测试,减少因实现变化导致的失败。
- 需要为难以测试的代码提供重构建议。
限制
该技能主要关注测试原则和结构,不涉及特定测试框架的详细配置或安装步骤。它假设用户已具备基本的测试环境。具体实现细节(如 MSW 的安装和配置)未在资料中提供。此外,该技能不涵盖性能测试、安全测试等特定领域。