1

我有一个异步动作创建器,它分为两个动作,一个表示动作的开始,另一个表示结束。异步动作创建者中间的 Web 请求依赖于第一次同步调度设置的值:

export function changeFilter(from, to) {
  return (dispatch, getState, { fetch }) => {
    // Updates the state with the new values and sets a loading flag
    dispatch(changeFilterRequest(from, to));

    // Now I want to use those newly-set values to build a query
    // string. However, the stubbed implementation of `dispatch`
    // doesn't use reducers, so `getState` continues to return the
    // original value.
    const { activeUsers } = getState();
    return doSomeWebRequest(fetch, activeUsersParams(activeUsers))
      .then(response => dispatch(changeFilterSuccess(response)))
  };
}

redux-mock-store 的 dispatch 的实现非常稀疏,而且(显然)事后看来,我们从不将任何 reducer 传递给 mocked store。

这意味着第一个dispatch调用没有机会更新第二个调度调用所依赖的状态。然后,我们发出的 Web 请求具有原始值tofrom日期,而不是来自异步操作调用的更新值。

我想避免直接使用传入的fromandto值,changeFilter因为可能会对changeFilterRequest. 直接依赖结果getState也将允许我干掉少数以不同方式过滤的类似方法。

对于这些类型的测试,我应该遵循什么模式吗?我应该以不同的方式来构建我的动作创建者吗?

4

1 回答 1

1

我认为您的单元测试应该是精确的,并且只关注您要测试的功能的范围,即changeFilter. 假设您有另一个单元测试来changeFilterRequest测试如何activeUsers计算并添加到 store ,activeUsers作为调度的副作用在 store 中创建的 事实changeFilterRequest应该超出您的测试范围,因为changeFilter不应该关心如何activeUsers计算。我认为您可以安全地在您的模拟商店中添加任何虚拟值,activeUsers该值不一定依赖于您传递给的值,to并确保您的函数从商店中正确读取该值并将其传递给.fromchangeFilterRequestactiveUsersParams

也就是说,我强烈推荐redux-saga作为redux-thunk处理异步操作的替代方案,因为它使测试这类操作变得容易,而无需创建模拟或测试副作用,因为您的所有操作都是纯的。

于 2016-11-10T16:52:25.513 回答