【问题标题】:Testing Complex Asynchronous Redux Actions测试复杂的异步 Redux 操作
【发布时间】:2017-03-04 18:11:24
【问题描述】:

所以,假设我有下一步行动:

export function login({ email, password, redirectTo, doNotRedirect }) {
  return ({ dispatch }) => {
    const getPromise = async () => {
      const basicToken = Base64.encode(`${email}:${password}`);
      const authHeaders = { Authorization: `Basic ${basicToken}` };
      const { payload, error } = await dispatch(sendAuthentication(authHeaders));

      if (error) throw payload;

      const { username, token, fromTemporaryPassword } = payload;
      const encodedToken = Base64.encode(`${username}:${token}`);

      dispatch(persistence.set('authorizationToken', encodedToken));
      dispatch(postGlobalId({ username }));
      dispatch(setIsLoggedIn(true));
      dispatch(setIsFromTemporaryPassword(fromTemporaryPassword));

      await dispatch(clientActions.fetchClient);

      if (doNotRedirect) return;

      if (fromTemporaryPassword)
        dispatch(updatePath('/profile/change-password'));
      else
        dispatch(updatePath(redirectTo || '/dashboard'));
    };

    return {
      type: AUTHENTICATION_LOGIN,
      payload: getPromise()
    };
  };
}

我想为它添加测试,以增加代码的可靠性。

所以,这里有几件事:

  1. 我们发送身份验证标头并获取数据作为响应
  2. 如果响应中存在错误,我们会抛出错误
  3. 我们设置了所有需要的令牌,发送所有需要的操作以表明我们现在已经登录了
  4. 获取客户端数据
  5. 根据参数和接收到的数据,我们重定向到需要的路由/不重定向

问题是测试真的太难了,我们需要对所有东西都进行存根,这很糟糕,因为测试很脆弱,脆弱性和对实现的了解太多(更不用说存根调度非常具有挑战性)正常工作)。

因此,我应该测试所有这 5 点,还是只关注最重要的东西,例如发送授权请求、抛出错误和检查重定向?我的意思是,所有标志都可以更改的问题,所以它不是那么可靠。

另一种解决方案是将这些活动分成如下内容:

  • auth
  • setLoginInfo
  • handleRedirects

并通过依赖注入传递所有需要的函数来调用(这里基本上只是使用参数)?使用这种方法,我只能监视调用此函数,而无需详细说明。

我对纯函数的单元测试和为它们处理不同的边缘情况非常满意(无需测试太多的实现,只测试结果),但测试具有副作用的复杂函数对我来说真的很难。

【问题讨论】:

  • 我的直觉是,您应该从 thunk 动作创建器中提取大量逻辑,并将其放入由动作创建器调用的单独实用程序函数中。您列出的 5 个步骤中的每一个都应该有自己的测试。
  • 但它不是一个实用函数,它完全是业务逻辑。是的,我可以让它们变得纯粹——但我基本上需要检查它们是否被调用,否则它的实现细节太多了。
  • 什么意思?我要说的是,这个动作创建者的逻辑太多了。您应该制作额外的函数,作为实用函数提供给动作创建者,以提高模块化。
  • 它们不能是utility函数,因为它们都有副作用。问题是如何将它们分开以及如何测试整个流程。
  • 你能给我链接一个说实用函数不能有副作用的资源吗?

标签: javascript unit-testing asynchronous redux redux-thunk


【解决方案1】:

如果您有这样非常复杂的操作,我认为另一种(更好的?)方法是使用简单的同步操作(您甚至可以直接分派有效负载,如果愿意,可以删除操作创建者,从而减少样板) ,并使用 redux-saga 处理异步端:https://github.com/yelouafi/redux-saga

Redux Saga 让您可以非常简单地将业务逻辑代码分解为多个可以单独测试的简单生成器函数。由于该库中的“调用”函数:http://yelouafi.github.io/redux-saga/docs/api/index.html#callfn-args,它们甚至可以在不调用底层 API 方法的情况下进行测试。由于使用了生成器,您的测试可以使用标准的 iterator.next 方法将值“输入”到 saga。最后,它们让 reducer 更容易发表意见,因为您可以从 store 状态中检查某些内容(例如使用选择器)来查看您的 saga 中接下来要做什么。

如果 Redux + Redux Saga 在我开始使用我的应用程序之前就已经存在(到目前为止大约有 100,000 个 JS(X) LOC),我肯定会使用它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-14
    • 2017-03-03
    • 2019-10-31
    • 2019-11-12
    • 2017-04-21
    • 2017-01-26
    • 1970-01-01
    相关资源
    最近更新 更多