React 测试库食谱 - 入门
自动化软件测试已成为软件开发中至关重要的组织流程,旨在确保预期的业务系统和产品功能能够按预期正常运行。在开发React.js前端应用程序时,React 测试库是官方推荐的工具,也是许多开发人员的首选,因为它鼓励良好的实践,它强制要求测试的重点不是实现细节,而是与网页与用户的交互方式非常相似。
这是系列文章的第一篇,该系列文章探讨了使用React 测试库测试前端应用程序的最佳实践。即使您不是 React.js 开发人员,也可以从中找到有用的信息,因为其底层概念与核心测试库相同。
如果您不熟悉软件测试理论,或者您不知道单元测试、集成测试、存根、模拟、测试替身等概念的含义,您应该查看一些软件测试参考,以确保使用相同的语言。
开始学习如何测试 React Web 应用程序的最佳地方可能是官方文档:
虽然官方文档很棒,但我还是发现自己花了太多时间在网上搜索完美的设置,试图弄清楚如何才能让我的测试更健壮,并让我对自己编写的代码更有信心。我两年前开始使用测试库,从那时起,我广泛地尝试了它的功能和局限性。我想分享这段经历以及我个人的测试秘诀。
在文章的最后,我与您分享了一个存储库,您可以将其用作参考或模板来设置您的项目。
让我们从基础概念开始简单讲解。
基本概念
自动化测试只是一段代码,用来检查另一段代码的正确性。但是,应该如何编写这段代码呢?设置测试的一种常用方法是“排列-执行-断言”模式:一种用于排列和格式化 UnitTest 方法中代码的模式。
- 安排所有必要的先决条件和输入。
- 对被测试的对象或方法采取行动。
- 断言预期的结果已经发生。
例如,此代码是一个简单的测试。
function sum(numbers: number[]): number {
return numbers.reduce((partial, current) => partial + current, 0);
}
function shouldSumAllNumbers() {
// Arrange
const input = [1, 2, 3];
// Act
const output = sum(input);
// Assert
if (output !== 6) {
throw new Error(`Test failed. Expected: 6, Actual: ${output}.`);
}
}
如果你问的是……是的,它和你可能在其他所有测试入门资源上都见过的“总和测试”没什么区别😴。我保证以后会讲到更多有趣的内容。
即使不是必需的,正如我之前所展示的,使用框架或一组测试实用程序编写和执行测试也会更加容易,尤其是在编写更复杂的测试(例如涉及 DOM 的测试)时。那么,让我们来设置测试环境。
设置环境
根据您的项目设置,您需要一些初始配置来在您的 React 应用程序上运行测试。
- 安装所需的依赖项
- 设置测试框架
- 开始测试!
使用Create React App创建的项目已开箱即用地支持 React Testing Library,您可以直接跳到微调步骤。使用其他工具链(例如Next.js和Gatsby.js)创建的项目需要执行以下步骤。如果您是完全的初学者,最好选择 CRA 并开始测试,而无需关心配置。如果您正在设置自定义工具链,那么这些步骤可能非常有用。
本指南做出了一些假设:
- Babel转译 JS/TS 文件并使用TypeScript 预设进行配置。
- Webpack用作捆绑器。
- 文件结构如下。
project-root/ // The root directory
|-src/ // Contains the JS/TS source code
|-test/ // Contains test config and utilities
|-config/ // Contains test config files
|-setupTests.js // The test env setup file
如果您使用其他设置,本指南仍然适用,但您可能需要调整一些部分,例如文件路径。如果您需要更高级的设置,可以查看Jest - 与 webpack 结合使用。
1.安装依赖项
首先,让我们安装所需的 npm 包。
npm i -D jest babel-jest @testing-library/jest-dom @testing-library/react @testing-library/user-event
我们刚刚安装了什么?
- jest:测试框架。它提供了测试环境、命令行工具、模拟 DOM、定义测试的函数(
describe
、it
、test
等)、模拟和监视实用程序、断言和期望函数。 - babel-jest:用于在测试中转译 JS 文件。它需要安装@babel /core。Babel 是一款流行的 JavaScript 转译器,但如何为你的项目配置 Babel 超出了本文的讨论范围。
- @testing-library/react:它在 DOM 测试库之上构建,添加了用于处理 React 组件的 API。
- @testing-library/jest-dom:为 Jest 提供自定义 DOM 元素匹配器。它扩展了我们可以使用的期望集。
- @testing-library/user-event:它是 Testing Library 的配套库,提供比内置
fireEvent
方法更高级的浏览器交互模拟。它不是必需的,但强烈建议使用。
2. 配置 Jest
Jest 的目标是在大多数 JavaScript 项目上开箱即用、免配置。但尽管如此,我还是更喜欢自定义配置来支持这三个功能。
- 添加对测试库和 TS 文件的支持。
- 存根文件导入
- 存根 CSS 导入
Jest 配置文件
jest.config.js
在项目根目录中创建一个文件。
module.exports = {
verbose: true,
roots: ["<rootDir>/src"],
collectCoverageFrom: ["src/**/*.{js,jsx,ts,tsx}", "!src/**/*.d.ts"],
setupFilesAfterEnv: ["<rootDir>/test/setupTests.js"],
testMatch: [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}",
],
testEnvironment: "jsdom",
transform: {
"^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/test/config/cssTransform.js",
"^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)":
"<rootDir>/test/config/fileTransform.js",
},
transformIgnorePatterns: [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",
"^.+\\.module\\.(css|sass|scss)$",
],
moduleFileExtensions: [
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
"node",
],
resetMocks: true,
};
此配置文件指示 Jest:
- 日志详细程度:
verbose
,我喜欢看看发生了什么🕵️。 - 源代码根目录:
src
文件夹。 - 代码覆盖率来源:JS/TS 文件(不包括 TS 声明文件)。
- 环境设置文件:该
setupTests.js
文件。我们稍后会看到它。 - 测试源
.test.js
:所有以或相应的 TS、JSX、TSX 变体结尾的文件.spec.js
。文件夹内的文件也__tests__
包含在内。 - 测试环境:Jest DOM
- 文件转换器:JS/TS 文件由 Babel 处理,CSS 文件和其他文件将需要自定义转换器,我们稍后会看到。
- 转换忽略文件:我们避免转换来自node_modules和 CSS 模块的源文件。
- 模块文件扩展名:我们支持的模块文件扩展名。
- 重置模拟:
true
Jest 在测试后自动重置模拟。
Jest 安装文件setupTests.js
在/test/中创建setupTests.js文件。
import "@testing-library/jest-dom";
它使用测试库自定义匹配器来指导 Jest。
CSS 转换器
创建文件/test/config/cssTransform.js。
"use strict";
module.exports = {
process() {
return "module.exports = {};";
},
getCacheKey() {
// The output is always the same.
return "cssTransform";
},
};
这是一个自定义的 Jest 转换器,用于将导入的样式转换为空对象。在我们的测试中,我们不需要导入真实的 CSS 文件。
文件转换
创建文件/test/config/fileTransform.js。
"use strict";
const path = require("path");
const camelcase = require("camelcase");
module.exports = {
process(src, filename) {
const assetFilename = JSON.stringify(path.basename(filename));
if (filename.match(/\.svg$/)) {
const pascalCaseFilename = camelcase(path.parse(filename).name, {
pascalCase: true,
});
const componentName = `Svg${pascalCaseFilename}`;
return `const React = require('react');
module.exports = {
__esModule: true,
default: ${assetFilename},
ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
return {
$$typeof: Symbol.for('react.element'),
type: 'svg',
ref: ref,
key: null,
props: Object.assign({}, props, {
children: ${assetFilename}
})
};
}),
};`;
}
return `module.exports = ${assetFilename};`;
},
};
在测试中,我们并不关心导入真实文件资源。这个自定义的 Jest 转换器负责:
- 将 SVG 文件转换为组件或字符串。在我们的应用中,我们可以使用
import svg from '../path/to/asset.svg'
和导入 SVGimport { ReactComponent as Asset } from '../path/to/asset.svg'
。 - 将其他资产(图像、视频等)转换为字符串。
开始测试您的组件
现在 Jest 已安装并配置完毕,我们可以设置测试脚本了。在package.json中添加或更新要运行的测试jest
脚本。无需额外的命令行参数,因为配置文件会处理自定义设置。
// package.json
{
"scripts": {
"test": "jest"
}
}
在命令行中启动
npm test -- --watch
(或)以监视模式运行测试。npx jest --watch
现在我们的测试环境已经准备好了🙌。让我们来编写第一个测试。
鉴于此App
组件:
function App() {
return (
<div>
<h1>Testing Library Recipes</h1>
<a href="https://testing-library.com/">Getting Started</a>
</div>
);
}
export default App;
此测试确保页面呈现链接。
import { render, screen } from "@testing-library/react";
import App from "./App";
it("Should contain a link", () => {
render(<App />);
const linkElement = screen.getByRole("link", { name: /getting started/i });
expect(linkElement).toBeInTheDocument();
});
该测试不依赖于任何实施细节,但它仅根据最终用户实际看到的内容做出假设,正如测试库的指导原则所述。
您的测试越类似于软件的使用方式,它们就越能给您信心。
运行npm test
控制台输出应该类似如下。
> jest
PASS src/App.test.tsx
✓ Should contain a link (71 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.726 s
Ran all test suites.
奖励:提交时运行测试
只有频繁运行测试,测试环境才能真正有效。最好的方法是设置一个持续集成服务器,在每次推送时自动运行测试。此外,在每次提交之前运行测试也很有用。这能让你更快地获得反馈,并防止你提交无效的代码。Husky是一个强大的
工具,可以帮助我们配置 Git 钩子来实现这一目标。
- 让我们在项目中安装并初始化 Husky!此命令将 Husky 安装为开发依赖项,并在我们的package.json
prepare
中添加一个脚本。
npx husky-init && npm install
你的package.jsonprepare
中应该有一个新的脚本。如果没有看到,请手动添加。
// package.json
{
"scripts": {
"prepare": "husky install"
}
}
- 安装 husky hooks 并运行准备脚本(或者您也可以直接运行
npx husky install
)。
npm run prepare
- 然后我们需要创建一个 Git
pre-commit
钩子。这个预提交钩子npm test
在提交之前运行。
npx husky add .husky/pre-commit "npm test"
如果npm test
命令失败,您的提交将自动中止。
随着测试套件的增长,执行时间可能会减慢您的开发进度。在每次提交之前在本地机器上运行所有测试可能会浪费时间。在这种情况下,在持续集成服务器上运行测试可能是更好的选择。但是,这不应该是一种全有或全无的方法:您可以将快速测试保留在提交前的钩子上(单元测试),并将较慢的测试移到持续集成流程上(端到端测试)。
GitHub Actions
GitHub Actions提供了一种自动化软件工作流程(包括持续集成)的简便方法,并且对公共仓库免费。
设置在推送时运行测试的 GitHub Action 是一个非常常见的工作流程,如果您切换到 GitHub 仓库页面上的“Actions”选项卡,GitHub 会推荐一个 Node.js 模板。但是,即使在将代码推送到 GitHub 之前,您也可以手动设置它并获得相同的结果。
对于此 CI 操作,GitHub 需要一个工作流配置文件,该文件定义了环境和要运行的命令。
为了快速开始,请在你的仓库目录node.js.yml
中创建一个文件.github/workflows
。文件内容如下。
name: Node.js CI
on:
push:
branches: [$default-branch]
pull_request:
branches: [$default-branch]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [12.x, 14.x, 15.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test
请记住将其替换$default-branch
为默认分支的名称(例如main
/ master
)。
此工作流程将全新安装 Node 依赖项,构建源代码并在不同版本的 Node 上运行测试。更多信息请参阅将Node.js 与 GitHub Actions 结合使用。
此模板适用于大多数用例,但您可以根据需要自定义 CI 流程。您可以直接在Github Actions 文档中阅读更多相关信息。
总结
准备测试需要以下步骤:
- 安装 Jest、测试库和所有必需的依赖项
- 配置 Jest
- 配置 Git 钩子
- 设置 GitHub Action
我留下了一个可以参考的项目模板。这是一个自定义的开发工具链,包含 React Testing Library、Jest、Husky、TypeScript、Babel、Webpack 和 React。
https://github.com/mbellagamba/testing-library-recipes
测试愉快!😃
文章来源:https://dev.to/mbellagamba/react-testing-library-recipes-getting-started-1agd