You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:00:05