IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> Jest 从入门到入坟 -> 正文阅读

[开发测试]Jest 从入门到入坟

前言

自动化测试

自动化测试有三种类型:Unit(单元测试)、Integration(集成测试)、End-to-end(端到端测试)

  • 单元测试: 单元测试是测试一个模块,不依赖任何外部资源
  • 集成测试: 测试一个模块或者多个模块,并伴随着它们对应的外部依赖资源,它测试的是应用代码的集成性,比如文件或者数据库。
  • 端对端测试: 依靠用户界面来驱动测试,这类测试可以保证很高的可靠性,但是它有两个很大的问题,第一个问题就是太慢了。因为每次测试都需要加载用户界面,每次测试都需要加载应用,也许还要用户登录,导航到指定页面,提交表单并检查结果,等等一系列,所以测试效率非常的慢 第二个问题就是太脆弱,因为一个程序、页面修改一下,如果 UI 变了,操作逻辑变了,就会彻底破坏这种测试

测试框架

测试框架给了我们一个包含很多工具的库,同时还给了我们一个测试的运行器
测试运行器会运行我们的测试,最常见的 3 个测试框架是 Jasmine、Mocha 和 Jest

  • Jasmine(茉莉) 是一个比较早期的参与者,无需插件
  • Mocha(摩卡) 曾经是 npm 上最受欢迎的框架,但是它设计的时候就没有包含其他框架的一些功能,所以需要开发者去添加插件,比较常见的插件是 Chai 和 Sinon
  • Jest(玩笑) 是 Facebook 出品,是目前主流的测试框架,基本上是 Jasmine 的一个翻版,如果用惯了 Jasmine 上手 Jest 也很快

jest

Jest 是一款优雅、简洁的 JavaScript 测试框架。

  • 无需配置: Jest 的目标是在大多数 JavaScript 项目中即装即用,无需配置。
  • 快照: 轻松编写持续追踪大型对象的测试,并在测试旁或代码内显示实时快照。
  • 隔离的: 并行进行测试,发挥每一丝算力。
  • 优秀接口: 从 it 到 expect - Jest 将工具包整合在一处。文档齐全、不断维护,非常不错。

基本使用

// 1.安装:yarn add --dev jest

// 2.index.js
function sum(a, b) {
  return a + b;
}

export default sum

// 3.sum.test.js
import sum from './index'

test('renders learn react link', () => {
  expect(sum(2,5)).toBe(7)
});


命令解释:

  • jest --watchAll # 执行所有测试并时时监听文件
  • jest --watch # 相当于执行 runs jest -o

执行结果相关:

  • % stmts是语句覆盖率(statement coverage):每个语句是否都执行了
  • % Branch分支覆盖率(branch coverage):条件语句是否都执行了
  • % Funcs函数覆盖率(function coverage):函数是否全都调用了
  • % Lines行覆盖率(line coverage):未执行的代码行数

命令行交互模式提示相关:

  • Press f to run only failed tests
    • f: 只会去跑之前没有通过的测试,修改完文件,在控制台按 f 就行
  • Press o to only run tests related to changed files
    • o 模式,它只会测试当前改变的文件,一定要配合 git 使用,–watchAll 改为 --watch,默认直接进入 o 模式
  • Press p to filter by a filename regex pattern
    • p:按测试文件名称的正则表达式来过滤哪些测试用例要执行
  • Press t to filter by a test name regex pattern
    • t:按测试用例名称的正则表达式来过滤哪些测试用例要执行
  • Press q to quit watch mode
    • q: 就直接是退出对代码的监控
  • Press Enter to trigger a test run
    • Enter: 重新运行测试

基本命令

# 测试命令
jest
# 初始化:基于您的项目,Jest将向您提出几个问题,并将创建一个基本的配置文件
jest --init # js
npx ts-jest config:init # ts
# 指定配置文件为 xxx.js 进行测试
jest --config xxx.js
# 指定测试单个文件
jest components/button/__test__/button.test.js
# 指定测试单个组件
jest components/button/*

配合 babel

// babel.config.js
// 文件用于配置与你当前Node版本兼容的Babel
// 需要的包:@babel/core, @babel/preset-env
module.exports = {
  presets: [
    ['@babel/preset-env', {targets: {node: 'current'}}],
    // '@babel/preset-typescript',  支持 ts
  ],
};

基本语法

匹配

  • toBe:object.is 相当于 ===
test('测试加法 3 + 7', () => {
  // toBe 匹配器 matchers object.is 相当于 ===
  expect(10).toBe(10)
})
  • toEqual:内容相等,匹配内容,不匹配引用
test('toEqual 匹配器', () => {
  // toEqual 匹配器 只会匹配内容,不会匹配引用
  const a = { one: 1 }
  expect(a).toEqual({ one: 1 })
})
  • toBeNull:只匹配 Null
  • toBeUndefined:只匹配 undefined,toBeDefined相反,匹配 null 是通过的
  • toBeTruthy:匹配任何 if 语句为 true (1、true…),toBeFalsy 与其相反
  • not:取反
test('not 匹配器', () => {
  const a = 1
  // 以下两个匹配器是一样的
  expect(a).not.toBeFalsy()
  expect(a).toBeTruthy()
})
  • toBeGreaterThan:大于;toBeLessThan:小于;toBeGreaterThanOrEqual:大于等于;toBeLessThanOrEqual:小于等于;toBeCloseTo:计算浮点数
  • toMatch: 匹配某个特定项字符串,支持正则
test('toMatch', () => {
  const str = 'http://www.zsh.com'
  expect(str).toMatch('zsh')
  expect(str).toMatch(/zsh/)
})
  • toContain:匹配是否包含某个特定项
test('toContain', () => {
  const arr = ['z', 's', 'h']
  const data = new Set(arr)
  expect(data).toContain('z')
})

jest 的钩子函数

  • beforeAll:在所有测试用例运行之前,会先调用 beforeAll 钩子函数
  • beforeEach:每个测试用例执行之前,都会调用,类似 vue-router 的 beforeEach,这样每次测试都是一个全新的实例,各个用例之间互不干扰。
  • afterEach:与 beforeEach 相反
  • afterAll:与 beforeAll 相反

jest 钩子函数的作用域

  • describe:把增加相关的代码放到一类分组中,相减的放到另一类分组中,可以使用 describe 分组 ,Jest 默认会在最外层套一个 describe
  • 不要在 describe 中写初始化的代码,避免踩坑,一定要写到钩子函数里

快照

  • 使用 toMatchSnapshot 匹配器
  • 运行后会在根目录生成一个 __snapshots__ 文件夹
  • 修改内容后与上次生成的快照进行比较,执行 jest --updateSnapshotjest -u 可更新快照
  • toMatchInlineSnapshot 会将快照生成到行内
// toMatchSnapshot
test('测试快照', () => {
  expect(...).toMatchSnapshot()
})

// toMatchInlineSnapshot
it('renders correctly', () => {
  // `` 中的内容是执行完后生成的
  expect(...).toMatchInlineSnapshot(`...`);
});

测试 React

你可以用像测试其他 JavaScript 代码类似的方式测试 React 组件。
现在有许多种测试 React 组件的方法。大体上可以被分为两类:

  • 渲染组件树 在一个简化的测试环境中渲染组件树并对它们的输出做断言检查。
  • 运行完整应用 在一个真实的浏览器环境中运行整个应用(也被称为“端到端(end-to-end)”测试)。

日前两种主要方法:Enzyme + JestReact Testing Library + Jest,官方推荐 React Testing Library + Jest 的方式

Enzyme

Enzyme(酶) 是 Airbnb开源的 React 测试类库 Enzyme 提供了一套简洁强大的 API,并通过 jQuery 风格的方式进行DOM 处理,开发体验十分友好。

Shallow 浅渲染

it('shallow`', () => {
    const wrapper = shallow(<MyComponent />);
    expect(wrapper.find('.icon-star')).to.have.length(1);
  });
it('renders children when passed in', () => {
  const wrapper = shallow(
          <MyComponent>
            <div className="unique" />
          </MyComponent>
  );
  expect(wrapper.contains(<div className="unique" />)).to.equal(true);
});

it('simulates click events', () => {
  const onButtonClick = sinon.spy();
  const wrapper = shallow(
          <Foo onButtonClick={onButtonClick} />
  );
  wrapper.find('button').simulate('click');
  expect(onButtonClick).to.have.property('callCount', 1);
});

Mount 完整的DOM渲染

it('mount', () => {
    const wrapper = mount(<MyComponent bar="baz" />);
    expect(wrapper.props().bar).to.equal('baz');
    wrapper.setProps({ bar: 'foo' });
    expect(wrapper.props().bar).to.equal('foo');
  });

  it('simulates click events', () => {
    const onButtonClick = sinon.spy();
    const wrapper = mount(
      <Foo onButtonClick={onButtonClick} />
    );
    wrapper.find('button').simulate('click');
    expect(onButtonClick).to.have.property('callCount', 1);
  });

  it('calls componentDidMount', () => {
    sinon.spy(Foo.prototype, 'componentDidMount');
    const wrapper = mount(<MyComponent />);
    expect(Foo.prototype.componentDidMount).to.have.property('callCount', 1);
    Foo.prototype.componentDidMount.restore();
  });

Render 静态渲染

it('render', () => {
    const wrapper = render(<MyComponent />);
    expect(wrapper.find('.xxx').length).to.equal(3);
  });

  it('renders the title', () => {
    const wrapper = render(<MyComponent title="unique" />);
    expect(wrapper.text()).to.contain('unique');
  });

快照

使用 enzyme-to-json 序列化进行快照比较,可在 jest.config.js 中进行配置 snapshotSerializers: ['enzyme-to-json/serializer'],也可直接使用

import Counter from './counter';

it('测试快照', () => {
  const {asFragment} = render(<Counter/>);
  expect(asFragment(<Counter />)).toMatchSnapshot();
});
  • React 16 中使用需要 enzyme-adapter-react-16

testing library

React 测试库是一组能让你不依赖 React 组件具体实现对他们进行测试的辅助工具。它让重构工作变得轻而易举,还会推动你拥抱有关无障碍的最佳实践。虽然它不能让你省略子元素来浅(shallowly)渲染一个组件,但像 Jest 这样的测试运行器可以通过 mocking 让你做到。

使用

AAA模式:编排(Arrange),执行(Act),断言(Assert)。

import React from "react";
import { render, fireEvent } from "@testing-library/react";

import Counter from "./app";

describe("<Counter />", () => {
  it("properly increments the counter", () => {
    // Arrange
    const { getByText } = render(<Counter />);
    const counter = getByText("0");
    const incrementButton = getByText("+");
    const decrementButton = getByText("-");

    // Act
    fireEvent.click(incrementButton);
    // Assert
    expect(counter.textContent).toEqual("1");

    // Act
    fireEvent.click(decrementButton);
    // Assert
    expect(counter.textContent).toEqual("0");
  });
});

编排(Arrange)

  • getByLabelText:搜索与作为参数传递的给定文本匹配的标签,然后查找与该标签关联的元素。

  • getByText:搜索具有文本节点的所有元素,其中的textContent与作为参数传递的给定文本匹配。

  • getByTitle:返回具有与作为参数传递的给定文本匹配的title属性的元素。

  • getByPlaceholderText:搜索具有占位符属性的所有元素,并找到与作为参数传递的给定文本相匹配的元素。

  • getBy:返回查询的第一个匹配节点,如果没有匹配的元素或找到多个匹配,则抛出一个错误。

  • getAllBy:返回一个查询中所有匹配节点的数组,如果没有匹配的元素,则抛出一个错误。

  • queryBy:返回查询的第一个匹配节点,如果没有匹配的元素,则返回null。这对于断言不存在的元素非常有用。

  • queryAllBy:返回一个查询的所有匹配节点的数组,如果没有匹配的元素,则返回一个空数组([])。

  • findBy:返回一个promise,该promise将在找到与给定查询匹配的元素时解析。如果未找到任何元素,或者在默认超时时间为4500毫秒后找到了多个元素,则承诺将被拒绝。

  • findAllBy:返回一个promise,当找到与给定查询匹配的任何元素时,该promise将解析为元素数组。

执行(Act)

// fireEvent(node: HTMLElement, event: Event)
fireEvent.click(incrementButton);

断言(Assert)

expect(counter.textContent).toEqual("1");
expect(counter.textContent).toEqual("0");

快照

import {render, fireEvent} from '@testing-library/react';

it('测试快照', () => {
  const {asFragment} = render(<Counter/>);
  expect(asFragment(<Counter />)).toMatchSnapshot();
});

对比

为什么 Enzyme 应该被弃用?
原因很多,大体上可以概括为几个要点:

  1. 它长期以来一直落后于 React 的前进步伐,因此在阻碍人们过渡到更新的 React 版本
  2. 它依赖于 React 的内部实现,React 团队不鼓励使用它
  3. 它目前只由一个人维护——对于这么多使用它的公司来说,只依靠一个人来维护他们的一个关键软件是有风险的
  4. 它助长了一些糟糕的测试实践,并且 Enzyme 中的测试无法代表客户体验
  5. 市面上有了一个更好的解决方案,这个行业已经在前进了
  1. enzyme 需要搭载对应的版本进行使用,版本滞后会导致影响使用
  2. react 官网推荐 rtl
  3. enzyme 通过 find 查找类进行对比,rtl 可使用丰富的查询 api 进行对比
  4. enzyme 通过 simulate函数创建 DOM 事件 ,rtl 使用 userEvent

参考文献

jest 中文文档
Zsh’s Blog
react 中文文档
enzyme 官网
testing-library 官网
enzyme-to-json github
enzymejs github
testing-library github
是时候说再见了,Enzyme.js
使用 React Testing Library 和 Jest 完成单元测试
comparing-enzyme-with-react-testing-library

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-08-10 13:44:36  更:2021-08-10 13:45:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 20:40:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码