跳到主要内容

组件测试

为什么要进行测试

  • 测试可以确保得到预期的结果
  • 作为现有代码行为的描述
  • 促使开发者写可测试的代码,一般可测试的代码可读性也会高一点
  • 如果依赖的组件有修改,受影响的组件能在测试中发现错误

测试类型

  • 单元测试:指的是以原件的单元为单位,对软件进行测试。单元可以是一个函数,也可以是一个模块或一个组件,基本特征就是只要输入不变,必定返回同样的输出。一个软件越容易些单元测试,就表明它的模块化结构越好,给模块之间的耦合越弱。React的组件化和函数式编程,天生适合进行单元测试
  • 功能测试:相当于是黑盒测试,测试者不了解程序的内部情况,不需要具备编程语言的专门知识,只知道程序的输入、输出和功能,从用户的角度针对软件界面、功能和外部结构进行测试,不考虑内部的逻辑
  • 集成测试:在单元测试的基础上,将所有模块按照设计要求组装成子系统或者系统,进行测试
  • 冒烟测试:在正式全面的测试之前,对主要功能进行的与测试,确认主要功能是否满足需要,软件是否能正常运行

Jest

Jest是Facebook开源的一个前端测试框架,主要用于React和React Native的单元测试,已被集成在create-react-app中。Jest特点:

  • 易用性:基于Jasmine,提供断言库,支持多种测试风格
  • 适应性:Jest是模块化、可扩展和可配置的
  • 沙箱和快照:Jest内置了JSDOM,能够模拟浏览器环境,并且并行执行
  • 快照测试:Jest能够对React组件树进行序列化,生成对应的字符串快照,通过比较字符串提供高性能的UI检测
  • Mock系统:Jest实现了一个强大的Mock系统,支持自动和手动mock
  • 支持异步代码测试:支持Promise和async/await
  • 自动生成静态分析结果:内置Istanbul,测试代码覆盖率,并生成对应的报告

globals API

  • describe(name, fn):描述块,讲一组功能相关的测试用例组合在一起
  • it(name, fn, timeout):别名test,用来放测试用例
  • afterAll(fn, timeout):所有测试用例跑完以后执行的方法
  • beforeAll(fn, timeout):所有测试用例执行之前执行的方法
  • afterEach(fn):在每个测试用例执行完后执行的方法
  • beforeEach(fn):在每个测试用例执行之前需要执行的方法

全局和describe都可以有上面四个周期函数,describe的after函数优先级要高于全局的after函数,describe的before函数优先级要低于全局的before函数

脚手架内置了通用单元测试框架Jest

项目测试时直接运行下面的指令

    "test": "react-scripts test",

项目启动测试

Jest will look for test files with any of the following popular naming conventions:

  • Files with .js suffix in tests folders.
  • Files with .test.js suffix.
  • Files with .spec.js suffix.

如果是Ts会包含ts结尾的文件

单独执行一个.test文件

    npx jest jest.test.js

React的特殊测试工具

  • ReactTestUtils 是官方提供的测试api,比较复杂难用
  • Airbnb 发布了一款叫作 Enzyme 的测试工具,通过它能够轻松对 React 组件的输出进行断言、操控和遍历。类似jQuery的获取方式
  • 官方推荐使用 React Testing Library,它使得针对组件编写测试用例就像终端用户在使用它一样方便。

React Testing Library

React Testing Library是一种简单轻量的测试工具,最新的脚手架已经内置了

    "@testing-library/jest-dom": "^4.2.4", 
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",

jest-dom

详细的文档可以去https://testing-library.com/docs/react-testing-library/api查看。

注意jest-dom是一个jest对于React的特殊断言库

  • Custom matchers
    • toBeDisabled
    • toBeEnabled
    • toBeEmpty
    • toBeEmptyDOMElement
    • toBeInTheDocument
    • toBeInvalid
    • toBeRequired
    • toBeValid
    • toBeVisible
    • toContainElement
    • toContainHTML
    • toHaveAttribute
    • toHaveClass
    • toHaveFocus
    • toHaveFormValues
    • toHaveStyle
    • toHaveTextContent
    • toHaveValue
    • toHaveDisplayValue
    • toBeChecked
    • toBePartiallyChecked
    • toHaveDescription
  • Deprecated matchers
    • toBeInTheDOM

官方创建了一个setupTests.ts文件在src下,导入了这个库

// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect';

user-event

user-event是一个测试库的配套库,它提供了比内置的fireEvent方法更高级的浏览器交互模拟。主要用来触发一些事件

  it("do active",()=>{
expect(menuElement).toBeInTheDocument();
let noActive = wrapper.getByText("no active");
expect(noActive).toBeInTheDocument();
expect(noActive).not.toHaveClass('menu-item is-active')
// 触发点击事件
fireEvent.click(noActive)
expect(noActive).toHaveClass('menu-item is-active')
expect(activeElement).not.toHaveClass('menu-item is-active')
})

异步断言 - Waiting for appearance

如果您需要等待一个元素出现,那么async wait实用程序允许您等待断言得到满足后再继续。等待实用程序会重试,直到查询通过或超时。

import { wait } from "@testing-library/react";

fireEvent.mouseEnter(dropdownElement)
await wait(() => {
expect(wrapper.queryByText('111')).toBeVisible()
})