React/Redux 应用程序的单元测试

Unit testing of React/Redux applications

我目前正在研究基于 Redux/React 的应用程序的测试方法。我通过了关于测试的 redux 教程,但仍有疑问:

  1. 仅 return 具有 typepayload 字段的对象来测试普通动作创建者是否有意义?对我来说,它闻起来像 getter/setter OO 应用程序中的测试。

  2. 在测试异步动作的情况下,你是否应该检查相应的成功动作并被调度?同样,在模拟 HTTP 请求的情况下,它似乎只是在测试模拟容器,而不是应用程序行为。

  3. 是否应该将测试重点放在减速器上,因为它们负责状态转换,意味着连接组件的行为?

  4. 也许与其测试应用程序的 redux 内核,不如在组件级别上进行更多测试?什么时候应该测试组件的哪些方面?这些测试是否脆弱?

我想听听在生产中使用 Redux/React 并积极进行测试的人们的一些经验。

我会依次回答每个问题,只是根据我的经验提供不同程度的详细信息。

tl dr:专注于特定于应用程序的行为和功能测试,让库担心 redux 实现细节并在组件中使用之前测试小型 reducer 函数。

  1. 如果你像我最初使用 redux 那样使用像 redux-actions 这样的抽象,那么就不是这样了。如果您一遍又一遍地手动返回具有相同属性的对象,只需设置一个简单的测试用例,循环遍历公开的动作创建者,使用值调用它们并检查返回的对象类型。对一些人来说有点矫枉过正,但当你有很多动作创造者时,它就变成了一种廉价的健全性检查。例如:

    for (var i = 0; i < actions.length; i++) {
      let action = actions[i](testData);
      expect(action).to.have.property('type');
      expect(action).to.have.property('payload');
    }
    
  2. 一个措辞混乱的问题,但无论如何经验告诉我过度测试与网络打交道的东西。涵盖由于超时导致的边缘情况,并提出一些关于对减速器的响应形状以及它们被调用的顺序的期望。

  3. 是的,它应该专注于减速器。这是最重要的问题,因为它关系到 redux 成功的原因之一。一切都是简单的函数组合成强大且易于推理的函数(reducer)。

    所以如果我们有:

    const reducer = combineReducers({
      a: reduceA,
      b: reduceB
    })
    

    然后在单独的测试用例中测试每个减速器的(reduceAreduceB)行为。您仍然希望测试返回的结果及其形状,但总是尝试在实现和测试中分解 reducer。

  4. 和以前一样,您应该使用小函数并在将其用于特定组件框架之前测试其实现(这里假设 react.js)。如果您遵循 docs

    中给出的建议

    It is advisable that only top-level components of your app (such as route handlers) are aware of Redux. Components below them should be presentational and receive all data via props.

    然后你所要做的就是测试顶级组件让 redux 的 dispatch 传入,然后测试简单组件是否调用像 onClick 这样的处理程序,或者从你的商店中提取正确的状态但这些应该只是简单的间谍或对道具的形状和价值的断言,与 redux 无关。

您可以尝试使用redux-actions-assertions来测试动作和动作创建者。它允许编写一行可读的断言,并避免存储准备阶段。