React 测试库食谱 - 入门

2025-06-07

React 测试库食谱 - 入门

自动化软件测试已成为软件开发中至关重要的组织流程,旨在确保预期的业务系统和产品功能能够按预期正常运行。在开发React.js前端应用程序时,React 测试库是官方推荐的工具,也是许多开发人员的首选,因为它鼓励良好的实践,它强制要求测试的重点不是实现细节,而是与网页与用户的交互方式非常相似。

这是系列文章的第一篇,该系列文章探讨了使用React 测试库测试前端应用程序的最佳实践。即使您不是 React.js 开发人员,也可以从中找到有用的信息,因为其底层概念与核心测试库相同

如果您不熟悉软件测试理论,或者您不知道单元测试、集成测试、存根、模拟、测试替身等概念的含义,您应该查看一些软件测试参考,以确保使用相同的语言。

开始学习如何测试 React Web 应用程序的最佳地方可能是官方文档:

虽然官方文档很棒,但我还是发现自己花了太多时间在网上搜索完美的设置,试图弄清楚如何才能让我的测试更健壮,并让我对自己编写的代码更有信心。我两年前开始使用测试库,从那时起,我广泛地尝试了它的功能和局限性。我想分享这段经历以及我个人的测试秘诀。

在文章的最后,我与您分享了一个存储库,您可以将其用作参考或模板来设置您的项目。

让我们从基础概念开始简单讲解。

基本概念

自动化测试只是一段代码,用来检查另一段代码的正确性。但是,应该如何编写这段代码呢?设置测试的一种常用方法是“排列-执行-断言”模式:一种用于排列和格式化 UnitTest 方法中代码的模式。

  1. 安排所有必要的先决条件和输入。
  2. 对被测试的对象或方法采取行动。
  3. 断言预期的结果已经发生。

例如,此代码是一个简单的测试。

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}.`);
  }
}
Enter fullscreen mode Exit fullscreen mode

如果你问的是……是的,它和你可能在其他所有测试入门资源上都见过的“总和测试”没什么区别😴。我保证以后会讲到更多有趣的内容。
即使不是必需的,正如我之前所展示的,使用框架或一组测试实用程序编写和执行测试也会更加容易,尤其是在编写更复杂的测试(例如涉及 DOM 的测试)时。那么,让我们来设置测试环境。

设置环境

根据您的项目设置,您需要一些初始配置来在您的 React 应用程序上运行测试。

  1. 安装所需的依赖项
  2. 设置测试框架
  3. 开始测试!

使用Create React App创建的项目已开箱即用地支持 React Testing Library,您可以直接跳到微调步骤。使用其他工具链(例如Next.jsGatsby.js)创建的项目需要执行以下步骤。如果您是完全的初学者,最好选择 CRA 并开始测试,而无需关心配置。如果您正在设置自定义工具链,那么这些步骤可能非常有用。

本指南做出了一些假设:

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
Enter fullscreen mode Exit fullscreen mode

如果您使用其他设置,本指南仍然适用,但您可能需要调整一些部分,例如文件路径。如果您需要更高级的设置,可以查看Jest - 与 webpack 结合使用

1.安装依赖项

首先,让我们安装所需的 npm 包。

npm i -D jest babel-jest @testing-library/jest-dom @testing-library/react @testing-library/user-event
Enter fullscreen mode Exit fullscreen mode

我们刚刚安装了什么?

  • jest:测试框架。它提供了测试环境、命令行工具、模拟 DOM、定义测试的函数(describeittest等)、模拟和监视实用程序、断言和期望函数。
  • 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 项目上开箱即用、免配置。但尽管如此,我还是更喜欢自定义配置来支持这三个功能。

  1. 添加对测试库和 TS 文件的支持。
  2. 存根文件导入
  3. 存根 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,
};
Enter fullscreen mode Exit fullscreen mode

此配置文件指示 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 模块的源文件。
  • 模块文件扩展名:我们支持的模块文件扩展名。
  • 重置模拟trueJest 在测试后自动重置模拟。

Jest 安装文件setupTests.js

/test/中创建setupTests.js文件。

import "@testing-library/jest-dom";
Enter fullscreen mode Exit fullscreen mode

它使用测试库自定义匹配器来指导 Jest。

CSS 转换器

创建文件/test/config/cssTransform.js

"use strict";

module.exports = {
  process() {
    return "module.exports = {};";
  },
  getCacheKey() {
    // The output is always the same.
    return "cssTransform";
  },
};
Enter fullscreen mode Exit fullscreen mode

这是一个自定义的 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};`;
  },
};
Enter fullscreen mode Exit fullscreen mode

在测试中,我们并不关心导入真实文件资源。这个自定义的 Jest 转换器负责:

  • 将 SVG 文件转换为组件或字符串。在我们的应用中,我们可以使用import svg from '../path/to/asset.svg'和导入 SVG import { ReactComponent as Asset } from '../path/to/asset.svg'
  • 将其他资产(图像、视频等)转换为字符串。

开始测试您的组件

现在 Jest 已安装并配置完毕,我们可以设置测试脚本了。在package.json中添加或更新要运行的测试jest脚本。无需额外的命令行参数,因为配置文件会处理自定义设置。

// package.json
{
  "scripts": {
    "test": "jest"
  }
}
Enter fullscreen mode Exit fullscreen mode

在命令行中启动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;
Enter fullscreen mode Exit fullscreen mode

此测试确保页面呈现链接。

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();
});
Enter fullscreen mode Exit fullscreen mode

该测试不依赖于任何实施细节,但它仅根据最终用户实际看到的内容做出假设,正如测试库的指导原则所述。

您的测试越类似于软件的使用方式,它们就越能给您信心。

运行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.
Enter fullscreen mode Exit fullscreen mode

奖励:提交时运行测试

只有频繁运行测试,测试环境才能真正有效。最好的方法是设置一个持续集成服务器,在每次推送时自动运行测试。此外,在每次提交之前运行测试也很有用。这能让你更快地获得反馈,并防止你提交无效的代码。Husky是一个强大的
工具,可以帮助我们配置 Git 钩子来实现这一目标。

  1. 让我们在项目中安装并初始化 Husky!此命令将 Husky 安装为开发依赖项,并在我们的package.jsonprepare中添加一个脚本
npx husky-init && npm install
Enter fullscreen mode Exit fullscreen mode

你的package.jsonprepare应该有一个新的脚本。如果没有看到,请手动添加。

// package.json
{
  "scripts": {
    "prepare": "husky install"
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. 安装 husky hooks 并运行准备脚本(或者您也可以直接运行npx husky install)。
npm run prepare
Enter fullscreen mode Exit fullscreen mode
  1. 然后我们需要创建一个 Gitpre-commit钩子。这个预提交钩子npm test在提交之前运行。
npx husky add .husky/pre-commit "npm test"
Enter fullscreen mode Exit fullscreen mode

如果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
Enter fullscreen mode Exit fullscreen mode

请记住将其替换$default-branch为默认分支的名称(例如main/ master)。

此工作流程将全新安装 Node 依赖项,构建源代码并在不同版本的 Node 上运行测试。更多信息请参阅将Node.js 与 GitHub Actions 结合使用
此模板适用于大多数用例,但您可以根据需要自定义 CI 流程。您可以直接在Github Actions 文档中阅读更多相关信息。

总结

准备测试需要以下步骤:

  1. 安装 Jest、测试库和所有必需的依赖项
  2. 配置 Jest
  3. 配置 Git 钩子
  4. 设置 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
PREV
Hacktoberfest - 为初学者做出贡献的想法 做出贡献的创造性方式 总结一下...
NEXT
实施微前端——发展遗留代码库的途径下一步是什么?