如何使用Jest测试React组件(附实例)

277 阅读7分钟

这篇文章是由特邀作者Jack Franklin撰写的。SitePoint的客座文章旨在为你带来JavaScript社区的著名作家和演讲者的引人入胜的内容。

在这篇文章中,我们将看看如何使用Jest--一个由Facebook维护的测试框架--来测试我们的React组件。我们会先看看如何在普通的JavaScript函数上使用Jest,然后再看看它提供的一些开箱即用的功能,这些功能的目的是使React应用的测试更加容易。

值得注意的是,Jest并不是专门针对React的:你可以用它来测试任何JavaScript应用程序。然而,它提供的一些功能在测试用户界面时非常方便,这就是为什么它与React非常匹配。

A Jester Juggling React Icons

示例应用程序

在我们可以测试任何东西之前,我们需要一个应用程序来测试为了忠实于Web开发的传统,我建立了一个小型的todo应用程序,我们将使用它作为起点。你可以在GitHub上找到它,以及我们将要写的所有测试。如果你想玩一玩这个应用程序来感受一下,你也可以在网上找到一个实时演示

该应用程序是用ES2015编写的,使用webpack和Babel ES2015和React预设进行编译。我不会去讨论构建设置的细节,但如果你想查看的话,都在GitHub repo中。你会在README中找到关于如何在本地运行该应用的完整说明。如果你想阅读更多信息,该应用程序是用webpack构建的,我推荐 "A Beginner's guide to webpack"作为该工具的良好介绍。

该应用程序的入口是app/index.js ,它只是将Todos 组件渲染到HTML中。

render(
  <Todos />,
  document.getElementById('app')
);

Todos 组件是应用程序的主要枢纽。它包含了所有的状态(这个应用程序的硬编码数据,在现实中可能来自API或类似的),并有代码来渲染两个子组件。Todo AddTodo ,它为状态中的每个todo渲染一次,并为用户添加一个新的todo提供表单。

因为Todos 组件包含了所有的状态,它需要TodoAddTodo 组件来通知它任何变化。因此,它向这些组件传递函数,当一些数据发生变化时,它们可以调用这些函数,而Todos 可以相应地更新状态。

最后,就目前而言,你会注意到所有的业务逻辑都包含在app/state-functions.js

export function toggleDone(todos, id) {…}

export function addTodo(todos, todo) {…}

export function deleteTodo(todos, id) {…}

这些都是纯函数,它们接收状态(对于我们的示例应用程序,是一个todos数组)和一些数据,并返回新状态。如果你对纯函数不熟悉,它们是只引用所给数据的函数,没有副作用。更多信息,你可以阅读我在A List Apart上关于纯函数的文章和我在SitePoint上关于纯函数和React的文章

如果你熟悉Redux,它们与Redux所说的reducer相当相似。事实上,如果这个应用变得更大,我会考虑进入Redux,以获得更明确的、结构化的数据处理方法。但对于这种规模的应用,你会发现本地组件的状态和一些良好的抽象函数就足够了。

TDD还是不TDD?

有很多关于测试驱动开发的优点和缺点的文章,在这些文章中,开发人员被期望先写测试,然后再写代码来修复测试。这背后的想法是,通过先写测试,你必须考虑你正在编写的API,它可以导致更好的设计。我发现这在很大程度上取决于个人的喜好,也取决于我所测试的东西的种类。我发现,对于React组件,我喜欢先写组件,然后对最重要的功能部分添加测试。然而,如果你发现先为你的组件编写测试适合你的工作流程,那么你应该这样做。这里没有硬性规定;做任何对你和你的团队感觉最好的事情。

介绍一下Jest

Jest首次发布于2014年,虽然最初获得了很多人的关注,但该项目有一段时间处于休眠状态,没有那么积极地进行工作。然而,Facebook在改进Jest方面投入了大量的精力,最近发布了几个版本,其变化令人印象深刻,值得重新考虑。与最初的开源版本相比,Jest的唯一相似之处是名称和标志。其他一切都被改变和重写了。如果你想了解更多,你可以阅读Christoph Pojer的评论,他在那里讨论了项目的现状。

如果你曾因使用其他框架设置Babel、React和JJSX测试而感到沮丧,那么我绝对建议你尝试一下Jest。如果你发现你现有的测试设置很慢,我也强烈推荐Jest。它能自动并行运行测试,其观察模式能够只运行与更改的文件相关的测试,当你有一个大的测试套件时,这是非常宝贵的。它配置了JSDom,这意味着你可以编写浏览器测试,但通过Node运行它们。它可以处理异步测试,并具有先进的功能,如mocking、spies和stubs内置。

安装和配置Jest

首先,我们需要安装Jest。因为我们也在使用Babel,所以我们将安装另外几个模块,使Jest和Babel能够很好地开箱即用,还有Babel和所需的预设。

npm install --save-dev jest babel-jest @babel/core @babel/preset-env @babel/preset-react

你还需要有一个babel.config.js 文件,其中配置了Babel,以便使用你需要的任何预设和插件。示例项目已经有了这个文件,它看起来像这样。

module.exports = {
  presets: [
    '@babel/preset-env',
    '@babel/preset-react',
  ],
};

这篇文章不会深入讨论设置Babel的问题。如果你想了解更多关于Babel的具体信息,我推荐Babel使用指南

我们还不会安装任何React测试工具,因为我们不打算从测试我们的组件开始,而是测试我们的状态函数。

Jest希望在__tests__ 文件夹中找到我们的测试,这在JavaScript社区已经成为一种流行的惯例,我们在这里也要坚持这样的做法。如果你不喜欢__tests__ ,Jest也支持查找任何.test.js.spec.js 文件。

由于我们将测试我们的状态函数,继续创建__tests__/state-functions.test.js

我们很快就会写一个合适的测试,但现在,先把这个假的测试放进去,这将让我们检查一切工作是否正常,我们是否配置了Jest。

describe('Addition', () => {
  it('knows that 2 and 2 make 4', () => {
    expect(2 + 2).toBe(4);
  });
});

现在,进入你的package.json 。我们需要设置npm test ,使其运行Jest,我们可以通过设置test 脚本来运行jest

"scripts": {
  "test": "jest"
}

如果你现在在本地运行npm test ,你应该看到你的测试在运行,并且通过了

PASS  __tests__/state-functions.test.js
  Addition
    ✓ knows that 2 and 2 make 4 (5ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 passed, 0 total
Time:        3.11s

如果你曾经使用过Jasmine,或者大多数测试框架,上面的测试代码本身应该是非常熟悉的。Jest让我们根据需要使用describeit 来嵌套测试。你使用多少嵌套由你自己决定。我喜欢嵌套我的测试,这样所有传递给describeit 的描述性字符串几乎都是一个句子。

当涉及到实际的断言时,你要把你想测试的东西包在一个expect() ,然后再对它调用一个断言。在本例中,我们使用了toBe 。你可以在Jest文档中找到所有可用断言的列表。toBe ,检查给定值是否与被测值相匹配,使用=== 。我们将通过本教程认识Jest的几个断言。

继续阅读《如何使用Jest测试React组件》,请点击SitePoint