• 赚钱入口【需求资源】限时招募流量主、渠道主,站长合作;【合作模式】CPS长期分成,一次推广永久有收益。主动打款,不扣量;

用Jest测试React应用程序的实用指南

JavaScript rin, seun 1年前 (2020-07-06) 284次浏览 0个评论

在本文中,我将向您介绍一个名为Jest的React测试工具,以及用于测试React组件的流行库Enzyme。我将向您介绍Jest测试技术,包括:运行测试,测试React组件,快照测试和模拟。如果您不熟悉测试并且不知道如何入门,那么本教程将对您有所帮助,因为我们将从测试简介开始。最后,您将启动并运行,使用Jest和Enzyme测试React应用程序。您应该熟悉React才能遵循本教程。

为什么要测试?

最好了解为什么我们要先做某事。那么,为什么要进行测试,其目的是什么?

  1. 测试的首要目的是防止回归。回归是先前已修复的错误的再现。在某个事件发生后,它会使功能停止按预期运行。
  2. 测试可确保复杂组件和模块化应用程序的功能。
  3. 为了使软件应用程序或产品有效运行,需要进行测试。

测试使应用程序更健壮,更不容易出错。这是一种验证您的代码是否可以实现您想要的功能以及您的应用是否按用户预期运行的方法。

单元测试

在此类测试中,将测试软件的各个单元或组件。单元可以是单个功能,方法,过程,模块或对象。单元测试隔离一部分代码并验证其正确性,以验证软件代码的每个单元是否按预期执行。

在单元测试中,将对单个过程或功能进行测试以确保其正常运行,并对所有组件进行单独测试。例如,测试功能或程序中的语句或循环是否正常运行将属于单元测试的范围。

组件测试

组件测试可验证应用程序各个部分的功能。在与其他组件隔离的情况下对每个组件执行测试。通常,React应用程序由几个组件组成,因此组件测试涉及单独测试这些组件。

例如,考虑一个具有不同网页且包含许多组件的网站。每个组件都有其自己的子组件。在不考虑与其他组件集成的情况下测试每个模块称为组件测试。

在React中进行这样的测试需要更复杂的工具。因此,我们需要Jest,有时还需要更复杂的工具,例如Enzyme,我们将在稍后对此进行简要讨论。

快照测试

快照测试可确保Web应用程序的用户界面(UI)不会意外更改。它会及时捕获组件的代码,以便我们可以将一种状态的组件与该组件可能采取的其他任何状态进行比较。

我们将在后面的部分中了解快照测试。

测试的优缺点

测试很棒,应该进行,但是它有优点也有缺点。

优点

  1. 它可以防止意外的回归。
  2. 它使开发人员可以专注于当前任务,而不用担心过去。
  3. 它允许应用程序的模块化构建,否则构建起来太复杂了。
  4. 它减少了手动验证的需要。

缺点

  1. 您需要编写更多代码,以及调试和维护。
  2. 非关键测试失败可能会导致应用程序在持续集成方面被拒绝。

JEST简介

Jest是一个令人愉悦的JavaScript测试框架,其重点是简单性。它可以与npm或Yarn一起安装。Jest适用于称为测试运行程序的更广泛的实用程序类别。它对React应用程序非常有效,但在React应用程序之外也很有效。

enzyme是用于测试React应用程序的库。它旨在测试组件,并且可以编写断言来模拟可确认UI是否正常工作的动作。

Jest和Enzyme很好地互补,因此在本文中我们将同时使用两者。

Jest进行测试的过程

在本节中,我们将安装Jest并编写测试。如果您不熟悉React,那么我建议您使用Create React App,因为它已经可以使用,并且随Jest一起提供。

npm init react-app my-app

我们需要安装enzyme****和enzyme-adapter-react-16react-test-renderer(数量应根据您正在使用的版本)。

npm install --save-dev enzyme enzyme-adapter-react-16 react-test-renderer

现在,我们已经使用Jest和Enzyme创建了项目,我们需要在项目setupTest.jssrc文件夹中创建一个文件。该文件应如下所示:

import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
configure({ adapter: new Adapter() });

这将导入enzyme并设置适配器以运行我们的测试。

在继续之前,让我们学习一些基础知识。本文中经常使用一些关键的东西,您需要了解它们。

  • ittest 您将一个函数传递给此方法,测试运行器将将该功能作为测试块执行。
  • describe 此可选方法用于将任意数量的itor test语句分组。
  • expect 这是测试需要通过的条件。它将接收到的参数与匹配器进行比较。它还使您可以访问许多匹配器,以使您可以验证不同的内容。您可以在文档中阅读有关它的更多信息。
  • mount 此方法呈现完整的DOM,包括我们正在其中运行测试的父组件的子组件。
  • shallow 这仅呈现我们正在测试的单个组件。它不呈现子组件。这使我们能够隔离地测试组件。

创建测试文件

Jest如何知道什么是测试文件,什么不是?第一条规则是,在任何目录中找到名称相同的文件__test__均被视为测试。如果将JavaScript文件放在这些文件夹之一中,则Jest会在调用Jest时尝试运行该文件,无论情况好坏。第二条规则是Jest将识别带有后缀.spec.js或的任何文件.test.js。它将搜索整个存储库中所有文件夹和所有文件的名称。

让我们为针对本教程创建的React微型应用程序创建第一个测试。您可以在Git ub 克隆它。运行npm install以安装所有软件包,然后npm start启动应用程序。检查README.md文件以获取更多信息。

让我们App.test.js开始编写我们的第一个测试。首先,检查我们的应用程序组件是否正确呈现以及是否已指定输出:

it("renders without crashing", () => {
  shallow(<App />);
});

it("renders Account header", () => {
  const wrapper = shallow(<App />);
  const welcome = <h1>Display Active Users Account Details</h1>;
  expect(wrapper.contains(welcome)).toEqual(true);
});

在上面的测试中,第一个测试使用进行,以shallow检查我们的应用程序组件是否正确呈现而不会崩溃。请记住,该shallow方法仅呈现单个组件,而没有子组件。

第二项测试检查我们是否h1在我们的应用程序组件中指定了标记输出“显示活动用户帐户”,并且Jest匹配器toEqual

现在,运行测试:

npm run test 
/* OR */
npm test

终端中的输出应如下所示:

  PASS  src/App.test.js
  √ renders without crashing (34ms)
  √ renders Account header (13ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        11.239s, estimated 16s
Ran all test suites related to changed files.

Watch Usage: Press w to show more.

如您所见,我们的测试通过了。它表明我们有一个名为的测试套件App.test.js,在Jest运行时有两个成功的测试。稍后我们将讨论快照测试,并且您还将看到测试失败的示例。

跳过或隔离测试

跳过或隔离测试意味着在Jest运行时,没有运行特定的标记测试。

it.skip("renders without crashing", () => {
  shallow(<App />);
});

it("renders Account header", () => {
  const wrapper = shallow(<App />);
  const header = <h1>Display Active Users Account Details</h1>;
  expect(wrapper.contains(header)).toEqual(true);
});

因为我们已经使用了skip隔离测试的方法,所以我们的第一个测试将被跳过。因此,当Jest运行时,它将不会运行或不会对我们的测试进行任何更改。仅第二个将运行。您也可以使用it.only()

对测试文件进行更改,然后不得不npm test再次手动运行,这有点令人沮丧。Jest有一个很好的功能,称为监视模式,它监视文件更改并相应地运行测试。要在监视模式下运行Jest,可以运行npm test -- --watchjest --watch。在本教程的其余部分中,我还建议让Jest在终端窗口中运行。

模拟功能

模拟是一个令人信服的对象或模块的副本,没有任何实际的内部构造。它可能只有一点点功能,但是与真实的东西相比,它是一个模拟。它可以由Jest自动创建,也可以手动创建。

我们为什么要嘲笑?模拟减少了依赖项的数量,即运行测试时必须加载和解析的相关文件的数量。因此,使用大量模拟可以使测试更快地执行。

模拟函数也称为“间谍”,因为它们使您可以监视由其他代码直接调用的函数的行为,而不仅仅是测试输出。

有两种模拟函数的方法:通过创建在测试代码中使用该模拟函数的模拟函数,或通过编写手动模拟来覆盖模块依赖性。

手动模拟****用于将模拟数据存入功能。例如,您可能不想创建访问网站或数据库之类的远程资源,而是要创建一个允许使用假数据的手动模拟。

我们将在下一部分中使用模拟函数。

测试React组件

本节将结合我们到目前为止在理解如何测试React组件方面获得的所有知识。测试涉及确保组件的输出没有意外地更改为其他内容。迄今为止,以正确的方式构造组件是确保成功进行测试的最有效方法。

我们可以做的一件事是测试组件的props-特别是测试是否将一个组件的props传递给另一组件。Jest和Enzyme API允许我们创建一个模拟函数来模拟道具是否在组件之间传递。

我们必须将用户帐户道具从主要App组件传递到该Account组件。我们需要提供用户帐户详细信息,Account以呈现用户的活动帐户。这是方便进行模拟的地方,使我们能够使用假数据测试组件。

让我们为user道具创建一个模拟:

const user = {
  name: "Adeneye David",
  email: "david@gmail.com",
  username: "Dave",
};

我们在测试文件中创建了一个手动模拟功能,并将其包装在组件周围。假设我们正在测试一个大型的用户数据库。不建议直接从我们的测试文件访问数据库。相反,我们创建了一个模拟函数,该函数使我们能够使用假数据来测试我们的组件。

describe("", () => {
  it("accepts user account props", () => {
    const wrapper = mount(<Account user={user} />);
    expect(wrapper.props().user).toEqual(user);
  });
  it("contains users account email", () => {
    const wrapper = mount(<Account user={user} />);
    const value = wrapper.find("p").text();
    expect(value).toEqual("david@gmail.com");
  });
});

上面我们有两个测试,我们使用一个describe图层,该图层接受了要测试的组件。通过指定我们希望测试通过的属性和值,我们可以继续进行。

在第一个测试中,我们检查传递给安装的组件的道具是否等于我们在上面创建的模拟道具。

对于第二项测试,我们将用户道具传递给已安装的Account组件。然后,检查是否可以找到与<p>组件中的元素相对应的元素Account。当我们运行测试套件时,您会看到测试成功运行。

我们还可以测试组件的状态。让我们检查错误消息的状态是否等于null:

it("renders correctly with no error message", () => {
  const wrapper = mount();
  expect(wrapper.state("error")).toEqual(null);
});

在此测试中,我们使用toEqual()匹配器检查组件错误的状态是否等于null 。如果我们的应用程序中出现错误消息,则测试将在运行时失败。

在下一节中,我们将介绍如何使用快照测试(另一种惊人的技术)来测试React组件。

快照测试

快照测试会及时捕获组件的代码,以便将其与存储在测试中的参考快照文件进行比较。它用于跟踪应用程序UI中的更改。

快照的实际代码表示形式是JSON文件,并且此JSON包含创建快照时组件外观的记录。在测试过程中,Jest在测试过程中将此JSON文件的内容与组件的输出进行比较。如果匹配,则测试通过。如果没有,则测试失败。

要将enzyme包装程序转换为与Jest快照测试兼容的格式,我们必须安装enzyme-to-json

npm install --save-dev enzyme-to-json

让我们创建快照测试。当我们第一次运行它时,该组件代码的快照将被组合并保存在目录中的新__snapshots__文件夹中src

it("renders correctly", () => {
  const tree = shallow(<App />);
  expect(toJson(tree)).toMatchSnapshot();
});

当上述测试成功运行时,会将当前的UI组件与现有的UI组件进行比较。

现在,让我们运行测试:

npm run test

测试套件运行时,将生成一个新快照并将其保存到该__snapshots__文件夹中。随后,当我们运行测试时,Jest将检查组件是否与快照匹配。

如上一节中shallow所述,Enzyme包中的该方法用于呈现单个组件,而没有其他任何东西。它不呈现子组件。相反,它为我们提供了一种在调试时隔离代码并获得更好信息的好方法。另一个名为的方法mount用于呈现完整的DOM,其中包括我们正在运行测试的父组件的子组件。

我们还可以更新快照,让我们对组件进行一些更改以使测试失败,这将发生,因为该组件不再与快照文件中的内容相对应。为此<h3>,我们将组件中的标签从更改<h3> Loading...</h3><h3>Fetching Users...</h3>。测试运行时,这将在终端中显示:

 FAIL  src/App.test.js (30.696s)
  × renders correctly (44ms)

  ● renders correctly

    expect(received).toMatchSnapshot()
    Snapshot name: `renders correctly
1

    - Snapshot
    + Received

      
        
          Display Active Users Account Details
        
        
    -     Loading...
    +     Fetching Users...
        
      

       7 | it("renders correctly", ()
=> {
       8 |   const wrapper = shallow();
    >  9 |   expect(toJson(wrapper)).toMatchSnapshot();
         |                           ^      10 | });
      11 |
      12 | /* it("renders without crashing", () => {

      at Object. (src/App.test.js:9:27)

 › 1 snapshot failed.
Snapshot Summary
 › 1 snapshot failed from 1 test suite. Inspect your code changes or press `u` to update them.

Test Suites: 1 failed, 1 total
Tests:       1 failed, 1 total
Snapshots:   1 failed, 1 total
Time:        92.274s
Ran all test suites related to changed files.

Watch Usage: Press w to show more.

如果我们希望测试通过,则可以将测试更改为以前的状态或更新快照文件。在命令行中,Jest提供了有关如何更新快照的说明。首先,w在命令行中按以显示更多,然后按u更新快照。

› Press u to update failing snapshots.

当我们按u更新快照时,测试将通过。

喜欢 (0)

您必须 登录 才能发表评论!