如何将测试从 Enzyme 迁移到 React Testing Library
如果你的 React 测试套件仍然依赖 Enzyme,那么你维护的代码所依赖的库已经多年没有收到官方更新了。Enzyme 没有针对 React 18 或 19 的适配器,非官方的变通方案也不可靠。前进的道路很明确:迁移到 React Testing Library (RTL)。
本文涵盖了成功完成 Enzyme 到 React Testing Library 迁移所需的概念转变、常见重构模式,以及为 2025 年处理此项工作的团队提供的实用指导。
核心要点
- Enzyme 缺乏针对 React 18 和 19 的官方适配器,这使得迁移到 React Testing Library 对现代 React 项目至关重要。
- RTL 专注于测试面向用户的行为而非实现细节,从而产生更稳定、更有意义的测试。
- 用 RTL 的
render()替换 Enzyme 的shallow()和mount(),并使用像getByRole()这样的可访问性查询来替代find()。 - 通过并行运行两个库并分批转换测试来实现增量迁移,从较简单的组件开始。
为什么 Enzyme 不再可行
Enzyme 曾是多年来占主导地位的 React 测试工具。但它与 React 内部实现的紧密耦合成为了一个负担。当 React 17 发布时,社区适配器填补了这个空白。React 18 完全打破了这种模式——没有官方适配器存在,也没有宣布会有,因为 Enzyme 项目实际上已经停止维护。
除了兼容性问题,Enzyme 还鼓励测试实现细节:检查内部状态、调用实例方法,以及使用浅渲染将组件与其子组件隔离。这些模式产生的脆弱测试即使在行为保持不变的情况下,也会在重构期间中断。
React Testing Library 采取了相反的方法。它完整地渲染组件,并以用户与之交互的方式查询 DOM——通过角色、标签和文本内容。这与现代 React 测试最佳实践保持一致,并产生在实现变更中保持稳定的测试。
核心理念转变
这次迁移中最大的挑战不是语法,而是思维方式。
Enzyme 测试通常看起来像这样:
- 通过
wrapper.instance()访问组件实例 - 直接调用
setState()或setProps() - 对内部状态值进行断言
- 使用
shallow()跳过子组件渲染
这些在 RTL 中都没有直接对应的方法。RTL 有意省略它们,因为它们测试的是用户永远看不到的东西。
相反,RTL 测试专注于:
- DOM 中渲染的内容
- 元素如何响应用户交互
- 是否存在可访问的角色和标签
要替换 Enzyme 的浅渲染,你需要渲染完整的组件树,并在需要时在模块级别模拟依赖项。这需要更多的设置,但能产生更有意义的覆盖率。
Discover how at OpenReplay.com.
常见重构模式
用 render() 替换 shallow() 和 mount()
RTL 的 render() 函数将你的组件挂载到 DOM 环境中。没有浅渲染的等效方法。如果子组件导致问题,可以使用 Jest 模拟它们:
jest.mock('./ChildComponent', () => () => <div data-testid="child-mock" />);
用可访问性查询替换 wrapper.find()
Enzyme 的 find('button') 变成 RTL 的 screen.getByRole('button')。优先使用反映用户如何定位元素的查询:
getByRole()用于交互元素getByLabelText()用于表单输入getByText()用于可见内容
移除 instance() 和 state() 断言
如果你正在测试点击按钮是否更新了内部状态,请重新构思测试:用户点击后看到了什么?对渲染的输出进行断言。
使用 findBy 和 waitFor 处理异步行为
Enzyme 需要手动调用 wrapper.update()。RTL 自动处理更新。对异步断言使用 findByRole() 或 waitFor()。
实际迁移是可行的
大型团队已经成功完成了这次迁移。Slack 工程团队使用基于 AST 的代码转换工具和 LLM 辅助转换的组合,转换了超过 15,000 个测试。纽约时报工程团队将他们的 Enzyme 迁移描述为 React 18 升级中最大的一部分工作。
常见的方法是:增量迁移。并行运行两个库。分批转换测试,从较简单的组件开始。在语法变更是机械性的地方使用自动化,但对于严重依赖实现细节的测试,预期需要手动工作。
React 19 和组件测试的未来
React 19 弃用了用于组件测试的 react-test-renderer,进一步巩固了 RTL 作为标准的地位。如果你正在计划 React 升级,首先完成 Enzyme 到 React Testing Library 的迁移可以消除一个主要障碍。
2025 年的现代 React 测试意味着编写能够在重构中存活、验证可访问性并反映真实用户行为的测试。RTL 在这三个方面都做到了。
结论
从 Enzyme 迁移需要的不仅仅是查找和替换。你正在采用一种不同的测试理念——一种优先考虑面向用户的行为而非内部实现的理念。这种努力在更稳定、更有意义且与当前和未来 React 版本兼容的测试中得到了回报。
从一小批开始。围绕用户看到的内容重新构思你的断言。放弃浅渲染。你的测试套件会因此变得更好。
常见问题
可以。两个库可以在同一个项目中共存。这允许你增量迁移测试而不会破坏现有的测试套件。在 Enzyme 旁边安装 RTL,分批转换测试,并在迁移完成后移除 Enzyme。
RTL 不鼓励直接测试内部状态。相反,测试可观察的结果。如果点击按钮改变了状态,验证用户在点击后看到的内容——例如更新的文本、出现的新元素或改变的属性。这种方法产生更有弹性的测试。
在模块级别使用 Jest 模拟有问题的子组件。这将你的测试与子组件的实现隔离开来,同时仍然完整地渲染父组件。使用 jest.mock 将子组件替换为简单的占位符元素。
是的。RTL 仍然是 React 19 推荐的测试库。React 19 弃用了用于组件测试的 react-test-renderer,使 RTL 成为标准选择。在升级到 React 19 之前完成迁移可以消除一个重大的兼容性障碍。
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.