Skip to main content

运行测试

注意: react-scripts@0.3.0 及更高版本提供此功能。

阅读迁移指南以了解如何在旧项目中启用它!

Create React App 使用 Jest 作为其测试运行器。 为了准备这个集成,我们做了 Jest 的 major revamp,所以如果你几年前听说过它的坏消息,再试一次。

Jest 是一个基于节点的运行器。 这意味着测试总是在 Node 环境中运行,而不是在真实的浏览器中运行。 这使我们能够实现快速迭代速度并防止片状。

虽然由于 jsdom,Jest 提供了诸如 window 之类的浏览器全局变量,但它们只是真实浏览器行为的近似值。 Jest 旨在用于逻辑和组件的单元测试,而不是 DOM 怪癖。

如果需要,我们建议你使用单独的工具进行浏览器端到端测试。 它们超出了 Create React App 的范围。

文件名约定

Jest 将查找具有以下任何流行命名约定的测试文件:

  • __tests__ 文件夹中带有 .js 后缀的文件。
  • .test.js 后缀的文件。
  • .spec.js 后缀的文件。

.test.js / .spec.js 文件(或 __tests__ 文件夹)可以位于 src 顶级文件夹下的任何深度。

我们建议将测试文件(或 __tests__ 文件夹)放在他们正在测试的代码旁边,以便相对导入看起来更短。 比如App.test.jsApp.js在同一个文件夹下,测试只需要import App from './App'就可以了,不需要很长的相对路径。 搭配还有助于在较大的项目中更快地找到测试。

命令行接口

当你运行 npm test 时,Jest 将以观看模式启动*. 每次保存文件时,它都会重新运行测试,就像 npm start 如何重新编译代码一样。

观察器包括一个交互式命令行接口,能够运行所有测试,或专注于搜索模式。 它以这种方式设计,以便你可以保持打开状态并享受快速重新运行。 你可以从观察者每次运行后打印的 “观看使用” 注释中学习命令:

Jest 监视模式

*虽然我们建议在开发期间以监视模式运行测试,但你可以通过传入 --watchAll=false 标志来禁用此行为。 在大多数 CI 环境中,这是为你处理的(请参阅 在 CI 服务器上)。

版本控制集成

默认情况下,当你运行 npm test 时,Jest 将只运行与自上次提交以来更改的文件相关的测试。 这是一项优化,旨在让你的测试快速运行,而不管你有多少测试。 但是,它假设你不经常提交未通过测试的代码。

Jest 总是会明确提到它只运行与自上次提交以来更改的文件相关的测试。 你还可以在监视模式下按 a 以强制 Jest 运行所有测试。

Jest 将始终在 持续集成 服务器上运行所有测试,或者如果项目不在 Git 或 Mercurial 存储库中。

编写测试

要创建测试,请添加带有测试名称及其代码的 it()(或 test())块。 你可以选择将它们封装在 describe() 块中以进行逻辑分组,但这既不是必需的也不推荐。

Jest 提供了一个内置的 expect() 全局函数来进行断言。 基本测试可能如下所示:

import sum from './sum';

it('sums numbers', () => {
expect(sum(1, 2)).toEqual(3);
expect(sum(2, 2)).toEqual(4);
});

Jest 支持的所有 expect() 匹配器都是 在这里广泛记录

你还可以使用 jest.fn()expect(fn).toBeCalled() 创建 “spies” 或模拟函数。

测试组件

组件测试技术范围很广。 它们的范围从验证组件在不抛出的情况下呈现的 “smoke test”,到浅层呈现和测试某些输出,再到完整呈现和测试组件生命周期和状态更改。

不同的项目根据组件更改的频率以及它们包含的逻辑量来选择不同的测试权衡。 如果你还没有决定测试策略,我们建议你从为你的组件创建基本的冒烟测试开始:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});

此测试安装一个组件并确保它不会在渲染期间抛出。 像这样的测试只需付出很少的努力就能提供很多价值,因此它们非常适合作为起点,这就是你将在 src/App.test.js 中找到的测试。

当你遇到由更改组件引起的错误时,你将更深入地了解它们的哪些部分值得在你的应用程序中进行测试。 这可能是引入更具体的测试断言特定预期输出或行为的好时机。

React 测试库

如果你想独立于它们呈现的子组件来测试组件,我们建议使用 react-testing-libraryreact-testing-library 是一个用于以类似于最终用户使用组件的方式测试 React 组件的库。 它非常适合 React 组件和应用程序的单元、集成和端到端测试。 它更直接地与 DOM 节点一起工作,因此建议与 jest-dom 一起使用以改进断言。

要安装 react-testing-libraryjest-dom,你可以运行:

npm install --save @testing-library/react @testing-library/jest-dom

或者你可以使用 yarn

yarn add @testing-library/react @testing-library/jest-dom

如果你想避免测试文件中的样板文件,你可以创建一个 src/setupTests.js 文件:

// react-testing-library renders your components to document.body,
// this adds jest-dom's custom assertions
import '@testing-library/jest-dom';

下面是使用 react-testing-libraryjest-dom 测试 <App /> 组件呈现 "学习 React" 的示例。

import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';

it('renders welcome message', () => {
render(<App />);
expect(screen.getByText('Learn React')).toBeInTheDocument();
});

详细了解 react-testing-library 提供的实用程序,以方便测试异步交互以及从 react-testing-library 文档examples 选择表单元素。

使用第三方断言库

我们建议你将 expect() 用于断言,将 jest.fn() 用于间谍。 如果你遇到问题,请 对 Jest 提起诉讼,我们会解决它们。 我们打算继续让它们更好地用于 React,例如支持 将 React 元素漂亮地打印为 JSX

但是,如果你习惯了其他库,例如 ChaiSinon,或者如果你有使用它们的现有代码并希望移植过来,则可以像这样正常导入它们:

import sinon from 'sinon';
import { expect } from 'chai';

然后像往常一样在测试中使用它们。

初始化测试环境

注意: react-scripts@0.4.0 及更高版本提供此功能。

如果你的应用程序使用你需要在测试中模拟的浏览器 API,或者如果你需要在运行测试之前进行全局设置,请将 src/setupTests.js 添加到你的项目中。 它将在运行测试之前自动执行。

例如:

src/setupTests.js

const localStorageMock = {
getItem: jest.fn(),
setItem: jest.fn(),
removeItem: jest.fn(),
clear: jest.fn(),
};
global.localStorage = localStorageMock;

注意: 请记住,如果你在创建 src/setupTests.js 之前决定使用 "eject",生成的 package.json 文件将不包含对它的任何引用,因此你应该在 Jest 的配置中手动创建属性 setupFilesAfterEnv,如下所示:

"jest": {
// ...
"setupFilesAfterEnv": ["<rootDir>/src/setupTests.js"]
}

聚焦和排除测试

你可以将 it() 替换为 xit() 以暂时排除正在执行的测试。

同样,fit() 可让你专注于特定测试,而无需运行任何其他测试。

覆盖率报告

Jest 有一个集成的覆盖率报告器,可以很好地与 ES6 配合使用并且不需要配置。

运行 npm test -- --coverage(注意中间有额外的 --)以包含如下覆盖率报告:

coverage report

请注意,覆盖范围内的测试运行速度要慢得多,因此建议将其与正常工作流程分开运行。

配置

可以通过将以下任何受支持的键添加到 package.json 中的 Jest 配置来覆盖 Create React App 用于 Jest 的 默认配置

支持的覆盖:

示例 package.json:

{
"name": "your-package",
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!<rootDir>/node_modules/",
"!<rootDir>/path/to/dir/"
],
"coverageThreshold": {
"global": {
"branches": 90,
"functions": 90,
"lines": 90,
"statements": 90
}
},
"coverageReporters": ["text"],
"snapshotSerializers": ["my-serializer-module"]
}
}

持续集成

默认情况下,npm test 使用交互式 CLI 运行观察器。 但是,你可以强制它运行一次测试并通过设置一个名为 CI 的环境变量来完成该过程。

使用 npm run build linter 创建应用程序构建时,默认情况下不会检查警告。 和npm test一样,可以通过设置环境变量CI强制构建执行linter警告检查。 如果遇到任何警告,则构建失败。

流行的 CI 服务器已经默认设置了环境变量 CI,但你也可以自己设置:

在 CI 服务器上

Travis CI

  1. 按照 Travis 入门 指南将你的 GitHub 存储库与 Travis 同步。 你可能需要在 profile 页面中手动初始化一些设置。
  2. .travis.yml 文件添加到你的 git 存储库。
language: node_js
node_js:
- 8
cache:
directories:
- node_modules
script:
- npm run build
- npm test
  1. 使用 git push 触发你的第一个构建。
  2. 自定义你的 Travis CI 构建 如果需要的话。

CircleCI

按照 this article 使用 Create React App 项目设置 CircleCI。

在你自己的环境中

Windows (cmd.exe)

set CI=true&&npm test
set CI=true&&npm run build

(注意:缺少空格是有意的。)

Windows (Powershell)

($env:CI = "true") -and (npm test)
($env:CI = "true") -and (npm run build)

Linux、macOS(Bash)

CI=true npm test
CI=true npm run build

test 命令将强制 Jest 在 CI 模式下运行,并且测试将只运行一次而不是启动 watcher。

对于非 CI 环境,你可以传递 --watchAll=false 标志来禁用测试观察。

build 命令将检查 linter 警告,如果发现则失败。

禁用 jsdom

如果你知道你的所有测试都不依赖于 jsdom,你可以安全地设置 --env=node,并且你的测试将运行得更快:

  "scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
- "test": "react-scripts test"
+ "test": "react-scripts test --env=node"

为了帮助你下定决心,这里列出了需要 jsdom 的 API:

相比之下,以下 API 不需要**jsdom:

最后,快照测试 也不需要 jsdom。

快照测试

快照测试是 Jest 的一项功能,它会自动生成组件的文本快照并将它们保存在磁盘上,因此如果 UI 输出发生变化,你会收到通知,而无需在组件输出上手动编写任何断言。 阅读有关快照测试的更多信息。

编辑器集成

如果你使用 Visual Studio Code,则有一个 Jest 扩展 可以开箱即用地与 Create React App 配合使用。 这在使用文本编辑器时提供了许多类似 IDE 的功能: 显示带有内联潜在失败消息的测试运行状态,自动启动和停止观察器,并提供一键式快照更新。

VS Code Jest 预览