使用Jest测试Redux时如何在每个测试用例后重置store?
Redux测试用例状态冲突解决方案
核心原则
测试用例之间完全隔离是单元测试的基本要求,Redux测试出现状态串扰的核心原因是多个测试复用了同一个store实例,没有在测试间隔清除上一个测试的状态变更。
主流实现方案
方案1:每个测试生成独立store(社区首推)
不需要改造任何生产代码,完全从测试侧解决问题,是最通用的方案:
- 封装独立的测试用store创建函数,支持传入自定义初始状态
- 借助Jest的
beforeEach钩子,在每个测试运行前都生成全新的store实例,所有测试的dispatch、状态读取操作都作用在这个新实例上
示例代码:
import { configureStore } from '@reduxjs/toolkit' import rootReducer from '你的rootReducer路径' // 封装测试store生成逻辑 const createTestStore = (preloadedState = {}) => { return configureStore({ reducer: rootReducer, preloadedState }) } let store // 每个测试启动前都初始化新store beforeEach(() => { store = createTestStore() }) // 测试用例直接使用store即可 test('添加用户', () => { store.dispatch(addUser({ id: 1, name: 'test' })) expect(store.getState().users.length).toBe(1) }) test('添加并删除用户', () => { store.dispatch(addUser({ id: 1, name: 'test' })) store.dispatch(deleteUser(1)) expect(store.getState().users.length).toBe(0) })
方案2:添加重置store的action(适合必须复用单store的场景)
如果你的测试场景有特殊要求必须复用同一个store实例,可以通过改造root reducer实现状态重置:
- 给root reducer增加
RESET_STORE的action处理逻辑,触发时返回应用初始状态 - 借助Jest的
afterEach钩子,在每个测试结束后触发重置action
示例代码:
// 改造root reducer import { combineReducers } from '@reduxjs/toolkit' import usersReducer from './usersSlice' const appReducer = combineReducers({ users: usersReducer, // 其他业务reducer }) export const rootReducer = (state, action) => { if (action.type === 'global/resetStore') { // 传入undefined作为state,会让所有子reducer返回自身初始状态 return appReducer(undefined, action) } return appReducer(state, action) } // 测试文件中添加重置逻辑 afterEach(() => { store.dispatch({ type: 'global/resetStore' }) })
注意事项
- 优先选择方案1,不需要侵入生产代码,也不会出现重置逻辑遗漏导致的状态残留问题
- 禁止在测试文件顶层初始化全局唯一的store实例,所有store的生成都要放在钩子函数或者单个测试内部
内容的提问来源于stack exchange,提问作者Amir M. Mohamadi
相关产品推荐
相关产品推荐

