如何比较两个Redux Store状态?Reducer测试中的状态差异校验
如何在Redux Reducer测试中校验仅指定字段变更
这问题我之前写Redux测试时也踩过坑,核心就是要先深拷贝旧状态,再精准对比新旧状态的差异。下面给你具体的实现方案:
第一步:深拷贝旧状态
Redux的状态是不可变对象,但直接赋值会拿到引用,所以必须用深拷贝来保存dispatch前的状态。推荐两种方式:
方式1:使用Lodash的cloneDeep(推荐复杂场景)
如果项目里已经有lodash,直接用最可靠的深拷贝方法:
import _ from 'lodash'; it('dispatch change', () => { // 深拷贝旧状态 const oldState = _.cloneDeep(store.getState()); store.dispatch(updateStoredCustomerDetails({ email: 'blabla@blabla.com' })); const newState = store.getState(); // 后续校验逻辑... });
方式2:原生JSON序列化(简单场景)
如果状态里没有函数、Symbol等JSON不支持的类型,可以用原生方法:
it('dispatch change', () => { const oldState = JSON.parse(JSON.stringify(store.getState())); store.dispatch(updateStoredCustomerDetails({ email: 'blabla@blabla.com' })); const newState = store.getState(); // 后续校验逻辑... });
第二步:校验仅邮箱字段变更
接下来要确保只有email字段变化,其余状态完全一致,这里有两种直观的校验方式:
方式1:拆分对象对比(最清晰)
把新旧状态中的email字段剔除,对比剩下的部分是否完全相等,同时单独校验邮箱的值:
it('dispatch change', () => { const oldState = _.cloneDeep(store.getState()); store.dispatch(updateStoredCustomerDetails({ email: 'blabla@blabla.com' })); const newState = store.getState(); // 1. 确认邮箱确实更新为目标值 expect(newState.customer.email).toBe('blabla@blabla.com'); // 2. 剔除邮箱字段后,其余状态完全一致 const { email: _, ...oldCustomerWithoutEmail } = oldState.customer; const { email: __, ...newCustomerWithoutEmail } = newState.customer; expect(newCustomerWithoutEmail).toEqual(oldCustomerWithoutEmail); // 如果整个store除了customer的email外都不变,还可以校验根状态的其他部分 const { customer: oldCustomer, ...oldRootWithoutCustomer } = oldState; const { customer: newCustomer, ...newRootWithoutCustomer } = newState; expect(newRootWithoutCustomer).toEqual(oldRootWithoutCustomer); });
方式2:自定义差异对比函数
写一个小工具函数,找出两个对象的所有差异,然后期望差异只有email字段:
// 工具函数:获取两个对象的差异(支持嵌套对象的浅层对比) function getObjectDiff(objA, objB) { return Object.keys(objA).reduce((diff, key) => { if (JSON.stringify(objA[key]) === JSON.stringify(objB[key])) { return diff; } return { ...diff, [key]: objB[key] }; }, {}); } it('dispatch change', () => { const oldState = _.cloneDeep(store.getState()); store.dispatch(updateStoredCustomerDetails({ email: 'blabla@blabla.com' })); const newState = store.getState(); // 获取customer对象的差异 const customerDiff = getObjectDiff(oldState.customer, newState.customer); // 期望差异仅包含email字段,且值正确 expect(customerDiff).toEqual({ email: 'blabla@blabla.com' }); });
额外建议
- 可以把深拷贝和差异对比的逻辑封装成测试工具函数,复用在其他Reducer测试中
- 避免用
console.log调试,直接用测试框架的断言来验证结果,这样测试更可靠
内容的提问来源于stack exchange,提问作者jeff
相关产品推荐
相关产品推荐

