菜单

测试 Redux 应用程序

相关源文件

本文档提供了有关如何有效测试 Redux 应用程序的全面指南。它涵盖了测试 Redux 代码的各个方面的方法、工具和最佳实践,包括 reducers、action creators、middleware 以及与 React 组件的集成。

有关 Redux 的 TypeScript 用法,请参阅 TypeScript 用法

概述和指导原则

Redux 应用程序因其可预测的状态管理和单向数据流而受益于测试。Redux 团队建议在测试 Redux 应用程序时遵循这些原则。

“你的测试越接近你的软件使用方式,它们就越能给你带来信心。” - Kent C. Dodds

对于 Redux 应用程序的测试,核心建议是:

  • 优先使用具有真实 Redux store 实例的集成测试,而不是隔离的 mock 测试。
  • 仅在需要时为复杂的 reducers 或 selectors 编写单元测试。
  • 不要 mock selector 函数或 React-Redux hooks。
  • 使用真实的 Redux store 来测试与 Redux 交互的组件。

来源:docs/usage/WritingTests.mdx1-38

设置测试环境

测试运行器

Redux 可以与任何测试运行器一起测试,尽管 Jest 和 Vitest 是常用的

  • Jest:由 Redux 库仓库使用,并附带 Create-React-App。
  • Vitest:Vite 项目的常见选择。

两个测试运行器都需要配置为编译 JavaScript/TypeScript,并提供具有 JSDOM 的模拟 DOM 环境以进行 UI 测试。

UI 和网络测试工具

Redux 团队推荐:

  • React Testing Library:用于测试连接到 Redux 的 React 组件。
  • Mock Service Worker (MSW):用于在不更改应用程序代码的情况下模拟网络请求。

来源:docs/usage/WritingTests.mdx39-72

集成测试连接的组件和 Redux 逻辑

推荐的方法是通过集成测试来测试 Redux 连接的组件,以验证完整的流程是否协同工作。

示例应用程序代码

考虑这个用户 slice 和获取用户数据的组件的简化示例。

  • userSlice.ts 包含用于获取用户的 reducers 和 async thunk。
  • store.ts 配置 Redux store。
  • UserDisplay.tsx 是一个显示和获取用户数据的组件。

设置可重用的测试渲染函数

要正确测试 Redux 连接的组件,您需要:

  1. 创建一个自定义渲染函数,该函数使用 `<Provider>` 包裹组件。
  2. 为每个测试创建一个新的 Redux store 实例。
  3. 允许传入可选的预加载状态。
  4. 同时返回渲染的元素和 store 实例。

这是这个自定义渲染函数样子的简化结构。

来源:docs/usage/WritingTests.mdx73-296

编写集成测试(带有组件)

一个合适的集成测试应该:

  1. 使用自定义渲染函数,并带 Redux store 来渲染组件。
  2. 设置 MSW 来模拟 API 响应。
  3. 测试完整的用户交互流程,包括:
    • 初始状态渲染。
    • 用户交互(点击按钮等)。
    • 异步状态更改。
    • 最终 UI 状态。

示例测试如下所示:

来源:docs/usage/WritingTests.mdx297-418

准备初始测试状态

为了设置特定的测试场景,您可以通过以下两种方式提供初始状态:

  1. preloadedState 传递给自定义渲染函数。
  1. 创建一个 store,分派 action 来构建状态,然后传递 store。

来源:docs/usage/WritingTests.mdx419-452

单元测试单个函数

虽然在大多数情况下推荐集成测试,但有时对单个 Redux 片段进行单元测试仍然是有价值的。

测试 Reducers

由于 reducers 是基于 action 转换状态的纯函数,因此它们很容易测试。

  1. 使用特定的 state 和 action 调用 reducer。
  2. 断言结果 state 符合预期。

示例

来源:[docs/usage/WritingTests.mdx:453-697],test/createStore.spec.ts1-546 test/combineReducers.spec.ts1-383

测试中间件

要测试 middleware,您需要:

  1. 创建一个 mock store 和 dispatch 函数。
  2. 创建一个您的 middleware 实例。
  3. 使用 mock store 和 next 函数调用 middleware。
  4. 断言 middleware 的行为符合预期。

测试文件中的示例

来源:test/applyMiddleware.spec.ts1-152 docs/usage/WritingCustomMiddleware.md1-118

测试 Thunks

Thunks 包含分派 action 的异步逻辑。要测试它们:

  1. 创建一个包含 thunk middleware 的 mock store。
  2. 将 thunk 分派到 mock store。
  3. 断言预期的 action 已被分派。

测试中的示例

来源:test/applyMiddleware.spec.ts67-116 test/helpers/actionCreators.ts17-33

使用 TypeScript 进行测试

在使用 TypeScript 测试 Redux 应用程序时,请确保您的测试正确键入:

  1. Redux store。
  2. Action creators 及其 payload。
  3. Reducers 及其 state。
  4. 用于 Redux 的自定义 hooks。

useAppDispatchuseAppSelector 这样的预定义 hooks,可以使测试 TypeScript Redux 应用程序更加容易。

来源:docs/usage/UsageWithTypescript.md1-726 docs/tutorials/typescript.md63-84 examples/counter-ts/src/app/hooks.ts1-7

测试 Redux 应用程序的最佳实践

测试策略

  • 从集成测试开始,涵盖主要的​​用户流程。
  • 仅为复杂的逻辑添加单元测试。
  • 测试行为,而不是实现细节。
  • 在测试中使用真实的示例数据。
  • 测试边缘情况和错误处理。

Redux 特定建议

  1. Store 设置:

    • 为每个测试创建一个新的 store。
    • 使用辅助函数创建 store。
    • 在测试 store 中包含必要的 middleware。
  2. 组件测试:

    • 使用真实的 Redux store 渲染组件。
    • 测试组件如何响应状态更改。
    • 测试分派 actions 的组件交互。
  3. Action 测试:

    • 测试 action 是否以正确的 payload 创建。
    • 对于异步 action,请测试从开始到完成的整个流程。
  4. Reducer 测试:

    • 测试初始状态。
    • 测试每种 action 类型的状态转换。
    • 测试状态更新是否是不可变的。

来源:docs/usage/WritingTests.mdx1-697

服务器端渲染测试

在测试具有服务器端渲染的 Redux 应用程序时,额外的注意事项包括:

  1. 测试状态从服务器到客户端的水合。
  2. 测试服务器上的初始状态生成。
  3. 测试完整的 SSR 过程。

对于 Next.js 应用程序:

  • App Router:测试每个请求的 store 创建以及使用 store 的客户端组件。
  • Pages Router:使用 next-redux-wrapper 库集成进行测试。

测试关键领域:

  • 服务器端渲染输出包含预期的 Redux 状态。
  • 客户端水合没有错误。
  • 路由更改保持正确状态。
  • Mutations 正确更新 store。

来源:docs/usage/nextjs.mdx29-408 docs/usage/ServerRendering.md1-210

结论

Redux 应用程序的测试受益于 Redux 本身的可预测性。通过专注于具有真实 store 实例的集成测试,您可以高置信度地测试完整的用户流程。单元测试对于复杂的边缘情况仍然有用,但次于集成测试。

有效 Redux 测试的关键在于尽可能使用真实的 Redux 逻辑,仅模拟 API 调用等外部依赖项,并验证 UI 是否根据用户交互和状态更改正确更新。

请记住,最终,用户并不关心您是否正在使用 Redux - 他们只关心应用程序是否正常工作。因此,请进行相应的测试,专注于用户行为而不是实现细节。

来源:docs/usage/WritingTests.mdx15-38