Angular单元测试:如何Mock数组中对象的更新操作
Redux Reducer UPDATE操作单元测试实现方案
看起来你已经搞定了GET和CREATE的reducer测试,接下来咱们来搞定UPDATE的测试。其实思路和之前的测试类似,因为reducer是纯函数,咱们不需要Mock复杂的外部依赖,只要构造好初始状态和对应的action,然后验证输出是否符合预期就行。
先回顾下你的reducer里UPDATE的逻辑:通过_id找到要更新的baby的索引,然后用新的payload替换掉原位置的对象,同时保持数组其他元素不变,而且用了tassign和扩展运算符来保证状态不可变,这点很棒。
那对应的测试用例可以这么写:
it('Should update a baby object in the babies array', () => { // 1. 构造带有初始babies的初始状态 const initialBabies = [ { _id: "5ad228ffdc32f1a42f5d3259", firstname: "Oliver", lastname: "Hultgren", username: "o@h", birthDate: new Date(2018, 0, 1), area: "København Ø", rating: [], userType: "baby", dataClient: "Julia" }, { _id: "5ad229d7dc32f1a42f5d325a", firstname: "Oli", lastname: "Hult", username: "o.h@dk", birthDate: new Date(2018, 0, 1), area: "København V", rating: [], userType: "baby", dataClient: "Julia" } ]; const initialState = { ...UsersService.getInitialUsersState(), babies: initialBabies }; deepFreeze(initialState); // 确保初始状态不会被突变 // 2. 构造要更新的baby对象(保持_id不变,修改部分字段) const updatedBaby = { _id: "5ad229d7dc32f1a42f5d325a", firstname: "Oliver Updated", // 修改名字 lastname: "Hultgren Updated", // 修改姓氏 username: "o.h@dk", birthDate: new Date(2018, 0, 1), area: "København Ø", // 修改地区 rating: [], userType: "baby", dataClient: "Julia" }; // 3. 构造预期的更新后状态 const expectedState = { ...initialState, babies: [ initialBabies[0], // 第一个baby保持不变 updatedBaby // 第二个baby被替换成更新后的对象 ] }; deepFreeze(expectedState); // 4. 调用reducer,传入初始状态和UPDATE action const newState = usersReducer(initialState, { type: types.UsersActions.UPDATED_BABY, payload: updatedBaby }); // 5. 验证结果 expect(newState).toEqual(expectedState); // 额外验证:确保更新后的数组长度不变 expect(newState.babies.length).toEqual(initialBabies.length); // 验证被更新的baby确实是修改后的内容 expect(newState.babies.find(b => b._id === updatedBaby._id)).toEqual(updatedBaby); });
测试逻辑拆解:
- 初始状态准备:我们在初始状态里加入了两个baby,这样可以验证更新操作只影响目标对象,其他对象不受影响。
- 更新对象构造:必须保证
_id和要更新的baby一致,同时修改几个字段,这样能明确看到更新效果。 - 预期状态构造:手动构建出我们期望reducer返回的状态,和实际结果做对比,这是单元测试的核心——验证输入输出的正确性。
- 不可变性验证:用
deepFreeze确保初始状态和预期状态都不会被意外修改,这也符合Redux的状态不可变原则。
关于Mock的问题:其实对于reducer的单元测试,因为reducer是纯函数(输入确定则输出确定,无副作用),我们不需要Mock任何外部服务或者API。你只需要构造正确的action(也就是Mock了action的结构),传入reducer就能测试逻辑是否正确。如果是测试action creator或者异步操作(比如thunk/saga)才需要Mock API请求,但这里只测试reducer的话,完全不需要复杂的Mock。
内容的提问来源于stack exchange,提问作者July333
相关产品推荐
相关产品推荐

