快速入门jest单元测试、mock测试、dom测试、快照测试

2023-11-04

 写在前面:本文参考然叔老师的全栈架构成长计划课程中的单元测试部分,对课程学习做了总结。有兴趣的可以去B站搜索“全栈然叔”,能够学习到比较前沿的东西。

一、单元测试

JavaScript 缺少类型检查,编译期间无法定位到错误,单元测试可以帮助你测试多种异常情况。测试可以验证代码的正确性,在上线前做到心里有底。通过 console 虽然可以打印出内部信息,但是这是一次性的事情,下次测试还需要从头来过,效率不能得到保证。通过编写测试用例,可以做到一次编写,多次运行。互联网行业产品迭代速度很快,迭代后必然存在代码重构的过程,那怎么才能保证重构后代码的质量呢?有测试用例做后盾,就可以大胆的进行重构。

简单来说,单元测试做的就是以下事情

  1. 引入要测试的函数
  2. 给函数一个输入
  3. 定义预期输出
  4. 检查函数是否返回了预期的输出结果

即:输入 —— 预期输出 —— 验证结果。

目录

一、单元测试

1.1 一个Jest Demo

1.2 jest断言函数

jest分组函数

jest 的钩子函数

jest 钩子函数的作用域

二、异步测试

一个异步测试的demo

新建src/delay.js文件

新建src/__test__/delay.spec.js测试文件

测试

提升异步测试效率

更改delay.spec.js

三、Mock测试

一个Mock测试的Demo

新增src/fetch.js

新增src/__test__/fetch.spec.js

测试

 jest的fn方法

 四、Dom测试

dom.js文件

dom.spec.js测试文件

安装jsdom

新增jsdom-config.js配置文件

 修改dom.spec.js文件

五、快照测试

新增snapshot.spec.js测试文件

测试


1.1 一个Jest Demo

jest 是facebook开源的一套js测试框架。中文文档:快速开始 · Jest

多刷刷官方文档,官方文档是最好的教程。

Jest 适用但不局限于使用以下技术的项目:Babel,、TypeScript、 Node、 React、Angular、Vue 等。jest规定每个代码里都有一套test目录,这个test目录对应相应的测试函数。test文件夹下某个文件(test.spec.js)与src文件夹下文件同名文件test.js是对应的映射关系。将实际代码与测试文件隔离放置,方便管理维护。

1、新建vue项目

初始化项目,生成package.json文件。

命令:npm init -y

2、安装 Jest

推荐全局安装,jest默认工作在当前工作区的npm 包下

命令:npm i jest -g

vscode安装jest类型提示,可以提示jest语法

npm i -D @types/jest

3、新增加法程序

src/add.js

新建src文件夹,新增add.js文件

const add = (a,b) => a+b;

module.exports = add;

4、新增测试类

src同级文件下新增__test__文件夹,并创建同名文件add.spec.js

//引入add方法
const add = require('../add')
//describe测试单元,用于分组
describe('',()=>{
    //比如,第一个测试用例,测试1+2是否为3
    //test第一个参数打印一段文本,第二个参数执行回调函数
    test('add(1,2) === 3',()=>{
        //断言 期待执行add(1,2)后返回结果是3,tobe表示期待的结果值
        expect(add(1,2)).toBe(3)
    })

    test('add(2,2)===4',()=>{
        expect(add(2,2).toBe(4))
    })
})
//第一个测试用例

上面的测试代码就像自然语言说话一样,很舒服。expect 称为断言函数:断定一个真实的结果是期望的结果。很多测试框架都有这个方法。

5、执行jest

直接在当前目录下执行jest,可以将所有的测试用例都执行一遍。

命令:test

1.2 jest断言函数

测试即运行结果是否与我们预期结果一致 断言函数用来验证结果是否正确

常用的断言方法

.toBe对值的判断

.toEqual类似于===全等判断

expect(运行结果).toBe(期望的结果);
//常见断言方法
expect({a:1}).toBe({a:1})//判断两个对象是否相等
expect(1).not.toBe(2)//判断不等
expect({ a: 1, foo: { b: 2 } }).toEqual({ a: 1, foo: { b: 2 } })
expect(n).toBeNull(); //判断是否为null
expect(n).toBeUndefined(); //判断是否为undefined
expect(n).toBeDefined(); //判断结果与toBeUndefined相反
expect(n).toBeTruthy(); //判断结果为true
expect(n).toBeFalsy(); //判断结果为false
expect(value).toBeGreaterThan(3); //大于3
expect(value).toBeGreaterThanOrEqual(3.5); //大于等于3.5
expect(value).toBeLessThan(5); //小于5
expect(value).toBeLessThanOrEqual(4.5); //小于等于4.5
expect(value).toBeCloseTo(0.3); // 浮点数判断相等
expect('Christoph').toMatch(/stop/); //正则表达式判断
expect(['one','two']).toContain('one'); //不解释

jest分组函数

describe("关于每个功能或某个组件的单元测试",()=>{

  // 不同用例的单元测试

})

jest 的钩子函数

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

jest 钩子函数的作用域

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

二、异步测试

如果测试函数中存在异步操作,且需要异步操作执行完才进行断言结果,单元测试函数需要设置done形参,在定时回调函数中调用。

一个异步测试的demo

新建src/delay.js文件

函数 delay表示延迟的意思,用延迟执行测试一下异步

module.exports = fn => {
    //设置1秒钟之后执行该延迟函数
    setTimeout(()=>fn(),1000);
};

新建src/__test__/delay.spec.js测试文件

it方法中的done函数表示程序执行结束,以此为标识进行测试

//引入 delay函数
const delay = require('../delay')
//异步测试
//done函数表示程序执行完成
it('异步测试',done => {
    delay(() =>{
        //等待定时器一定时间后调用delay函数执行
        done()
    })
    expect(true).toBe(true)
})

测试

命令:jest delay

提升异步测试效率

由于异步测试会根据程序中的等待时间而进行等待,可以通过jest.useFakeTimers()方法提升效率。简单来说就是模拟一个时间函数,让时间函数进行一个快进的处理。

更改delay.spec.js

//引入 delay函数
const delay = require('../delay')
//异步测试
//done函数表示程序执行完成
it('异步测试',done => {
    //.useFakeTimers()使用虚拟时钟,在执行过程中进行拨快
    jest.useFakeTimers()
    delay(() =>{
        //等待定时器一定时间后调用delay函数执行
        done()
    })
    //.runAllTimers()在调用完成后,拨快时钟
    jest.runAllTimers()
    expect(true).toBe(true)
})

命令:jest delay

可以看到测试时间得到了显著的提示

三、Mock测试

vue项目开发中调用其他库信息时,就不是单元测试了。

mock函数相当于制造了一个虚拟函数

一个Mock测试的Demo

安装axios

命令:npm i axios -s

新增src/fetch.js

const axios = require('axios')
//定义一个getData方法,通过axios.get方法获取某个接口数据
exports.getData = () => axios.get('/abc/bcd');

新增src/__test__/fetch.spec.js

const {getData} = require('../fetch')
const axios = require('axios')
//mock方法
jest.mock('axios')
it('测试fetch',async()=>{

    //根据行为模拟mock对象
    //假设已知fetch.js中的axios.get方法返回一个promise对象值为'123'
    axios.get.mockResolvedValueOnce('123')
    axios.get.mockResolvedValueOnce('456')
    const data1 = await getData()
    const data2 = await getData()
    //断言结果'123'
    expect(data1).toBe('123')
    expect(data2).toBe('456')
})

测试

jest fetch

如果返回的值与预期不符

jest会进行提示,expect期待的值是什么,receive接收到的值是什么

 jest的fn方法

jest.fn()是创建Mock函数最简单的方式,如果没有定义函数内部的实现,jest.fn()会返回undefined作为返回值

在上面异步测试的方法中新增一个测试用例,检测mockFn是否被调用

//引入 delay函数
const delay = require('../delay')
//异步测试
//done函数表示程序执行完成
it('异步测试',done => {
    //.useFakeTimers()使用虚拟时钟,在执行过程中进行拨快
    jest.useFakeTimers()
    delay(() =>{
        //等待定时器一定时间后调用delay函数执行
        done()
    })
    //.runAllTimers()在调用完成后,拨快时钟
    jest.runAllTimers()
    expect(true).toBe(true)
})

it('异步测试 fn',done => {
    //定义一个mockFn函数,该函数本身可以被断言
    let mockFn = jest.fn()
    jest.useFakeTimers()
    delay(() =>{
        mockFn()
        done()
    })
    jest.runAllTimers()
    expect(true).toBe(true)
    //断言mockFn是否被断言
    expect(mockFn).toBeCalled()
})

执行 jest delay后成功

 如果将mockFn()调用注释掉,执行报错

 四、Dom测试

所谓Dom测试是为了验证前端程序对Dom的操作是否正确。为了测试方便,又不希望在浏览器环境中进行这时就可以在Node环境中进行,但是Node中并没有Dom模型。解决办法就是使用jsdom进行Dom的仿真。

dom.js文件

//创建一个div的元素
exports.generateDiv = () => {
    const div = document.createElement('div')
    //修改div的属性
    div.className = 'c1'
    //添加到文档对象模型中
    document.body.appendChild(div)
}

dom.spec.js测试文件

const {generateDiv} = require('../dom')
it('Dom测试',()=>{
    generateDiv()
})

命令:jest dom

jest dom测试结果

直接运行dom测试案例会报错

安装jsdom

根据报错提示使用jsdom工具测试Dom元素

命令:npm i jsdom -s

新增jsdom-config.js配置文件

//引入jsdom
const jsdom = require('jsdom') // eslint-disable-line
const { JSDOM } = jsdom
//jsdom实现对真实dom方针
const dom = new JSDOM('<!DOCTYPE html><head/><body></body>', {
  url: 'http://localhost/',
  referrer: 'https://example.com/',
  contentType: 'text/html',
  userAgent: 'Mellblomenator/9000',
  includeNodeLocations: true,
  storageQuota: 10000000,
})
//浏览器包括window对象和document对象
//将dom绑定到全局 dom对象的window属性绑定到全局的window属性
global.window = dom.window
global.document = window.document
global.navigator = window.navigator

 修改dom.spec.js文件

引入jsdom-config.js文件,重新执行测试

命令:jest dom

可以发现测试正常通过

五、快照测试

快照测试使用jest的 toMatchSnapshot 匹配器,运行后会在根目录生成一个 __snapshots__ 文件夹。

修改内容后与上次生成的快照进行比较,执行jest --updateSnapshot 或 jest -u 可更新快照

执行toMatchInlineSnapshot 会将快照生成到行内

快照测试其实是将对象实例进行序列化,转成文件的形式进行持久化保存。等到下次测试的时候与之比较。快照测试广泛应用于ui测试。就比如说在前端测试中,可以Dom对象做成快照。每当你想要确保你的UI不会有意外的改变,快照测试是非常有用的工具。典型的做法是在渲染了UI组件之后,保存一个快照文件, 检测他是否与保存在单元测试旁的快照文件相匹配。 若两个快照不匹配,测试将失败:有可能做了意外的更改,或者UI组件已经更新到了新版本。

接下来我们使用快照测试测试Dom元素

新增snapshot.spec.js测试文件

//引入dom
const {generateDiv} = require('../dom')
//引入jsdom-config
require('../jsdom-config')
//快照测试
test('Dom的快照测试',()=>{
    generateDiv()
    //toMatchSnapshot 和上次的快照进行比对
    expect(document.getElementsByClassName('c1')).toMatchSnapshot()
})

测试

命令:test snapshot

执行后可以看到__test__目录下新增了一个snapshots文件。这里就是存放的快照文件

再次测试时快照文件不更新

命令:test snapshot

假设修改dom.js文件中的div类名,再次执行测试可以看到快照测试结果发生了变化。

 快速入门,你入门了吗

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

快速入门jest单元测试、mock测试、dom测试、快照测试 的相关文章

随机推荐

  • 华为OD机试 - 按单词下标区间翻转文章内容(Java)

    题目描述 给定一段英文文章片段 由若干单词组成 单词间以空格间隔 单词下标从0开始 请翻转片段中指定区间的单词顺序并返回翻转后的内容 例如给定的英文文章片段为 I am a developer 翻转区间为 0 3 则输出 developer
  • HJ26 字符串排序

    Powered by NEFU AB IN Link 文章目录 HJ26 字符串排序 题意 思路 代码 HJ26 字符串排序 题意 编写一个程序 将输入字符串中的字符按如下规则排序 规则 1 英文字母从 A 到 Z 排列 不区分大小写 如
  • PCL 计算点云法向量并显示

    目录 一 算法原理 1 法向量估计 2 法向量定向 3 表面曲率 4 参考文献 5 法向量定向的理解 6 CloudCompare 二 pcl Normal的定义 三 pcl Normal的几种输出方式 四 计算法线并显示 1 计算输入点云
  • 单点登录(简单的实现)

    假设现在有两个域名 分别为 分别记为client1 client2 client1 com client2 com 一个认证服务器 域名 ssoserver com client1 client2都需要登陆后才能访问到数据 现在想要实现cl
  • 76-C语言-输入班级学生的姓名和三科成绩,按总分排名

    问题 输入50分学生的姓名和三科成绩 按降序输出名字和总分 成绩相同的并列排名 思路 因为要学生排名 且一个学生有姓名 成绩 以及总分 所以弄一个学生的结构体 有多少学生 就输入该结构体的数组 一个for循环 给每个学生赋值 排序 降序 用
  • 【c++中的细节问题】关于typedef的详细用法

    请见 C C typedef用法详解 真的很详细 superhoy的专栏 CSDN博客 c typedef
  • 3.Linux文件管理和 I/O 重定向

    Linux文件管理和 I O 重定向 Linux文件系统目录结构 常见目录说明 根目录 一般根目录下只存放目录 在Linux下有且只有一个根目录 所有的东西都是从这里开始 当你在终端里输入 home 你其实是在告诉电脑 先从 根目录 开始
  • 利用多线程批Put方式压测HBase

    利用多线程批Put方式压测HBase 背景 在正式上生产之前 一定要对集群的组件做稳定性和性能压测 这是常识 这种压测当然不能指望那些只会鼠标点几下网页并经常指责前端页面样式有bug的测试去做 这种稍微有点技术含量的事情 她们其实有心无力
  • Mybatis中的#号与$符号的区别

    1 变量名 可以进行预编译 类型匹配等操作 2 变量名 会转化为jdbc的类型 3 变量名 不进行数据类型匹配 直接替换 4 方式能够很大程度防止sql注入 5 方式无法方式sql注入 6 方式一般用于传入数据库对象 例如传入表名 7 尽量
  • List取交集、并集、差集

    突然被面试官问到这样一个问题 List怎么取交集 我想了一会后说道双重循环 自己都觉得面试官想要的答案应该不是这个 效率太低了 后面问面试官答案 面试官告诉我可以将其中一个llist转成一个map或set 再遍历第二个list的时候判断 m
  • Vision Transformer

    A N I MAGE IS W ORTH 16 X 16 W ORDS TRANSFORMERS FOR I MAGE R ECOGNITION AT S CALE 原文链接地址 https arxiv org abs 2010 11929
  • shell学习:从ini文件中读取参数

    打算编写一个shell脚本来自动备份网站 需要从配置文件中读取一些参数 比如数据库名称 用户名和密码等 我分析了一下wdcp自带的数据库备份脚本mysqlbackup sh 里面仅仅从文件mrpw conf中读取了数据库密码 只用到了cat
  • 面试前需考虑的25个问题

    我曾经在The Simple Dollar上提到自己过去曾组织了大量面试工作 虽然我招聘的通常是技术类职位 但实际问到的问题 因此是有实际价值的 都是无关技术的 一个好的面试问题能使应聘者的本性显露出来 诚实 可信 反应敏锐等等 长期以来
  • vue项目嵌入iframe后访问后端报错

    项目场景 最近的项目中 开发的项目中需要使用到另外的一个即时通讯im项目 当时使用ifram标签进行嵌入 跳转失败 问题描述 在使用ifram进行嵌入后 刷新页面 ifram的地址会直接覆盖掉父类地址进行网页跳转 原因分析 在嵌入的src地
  • 车牌识别系统Matlab算法实现

    车牌识别系统Matlab算法实现 标签 车牌识别 2014 10 29 10 51 1408人阅读 评论 0 收藏 举报 本文章已收录于 分类 机器学习 21 作者同类文章 X plain view plain copy print
  • MindSpore报错“TypeError: parse() missing 1 required positional.“

    1 报错描述 1 1 系统环境 ardware Environment Ascend GPU CPU CPU Software Environment MindSpore version source or binary 1 6 0 Pyt
  • C++知识整理系列(三)—— constexpr常量表达式

    const修饰常量 但是const并未区分编译时常量和运行时常量 而constexpr则只能是编译时常量 在C 11中提出 这篇文章 将详细讲解constexpr 目录 一 常量表达式 二 constexpr变量 三 constexpr函数
  • H264与MPEG中I、P、B帧编码的不同

    暂时没时间去研究I P B帧是否真的在H 264与MPEG中不一样 先转过来 1 H264中I P B 帧编码的基本流程 I 帧编码的基本流程为 1 进行帧内预测 决定所采用的帧内预测模式 2 像素值减去预测值 得到残差 3 对残差进行变换
  • php结合layui前端实现 多图上传

    1 效果图 效果图上完了 就开始代码咯 2 前端html代码 div class layui upload div
  • 快速入门jest单元测试、mock测试、dom测试、快照测试

    写在前面 本文参考然叔老师的全栈架构成长计划课程中的单元测试部分 对课程学习做了总结 有兴趣的可以去B站搜索 全栈然叔 能够学习到比较前沿的东西 一 单元测试 JavaScript 缺少类型检查 编译期间无法定位到错误 单元测试可以帮助你测