当前位置: 首页 > news >正文

【实战】一、Jest 前端自动化测试框架基础入门(三) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(三)

文章目录

    • 一、Jest 前端自动化测试框架基础入门
      • 7.异步代码的测试方法
      • 8.Jest 中的钩子函数
      • 9.钩子函数的作用域


学习内容来源:Jest入门到TDD/BDD双实战_前端要学的测试课


相对原教程,我在学习开始时(2023.08)采用的是当前最新版本:

版本
@babel/core^7.16.0
@pmmmwh/react-refresh-webpack-plugin^0.5.3
@svgr/webpack^5.5.0
@testing-library/jest-dom^5.17.0
@testing-library/react^13.4.0
@testing-library/user-event^13.5.0
babel-jest^27.4.2
babel-loader^8.2.3
babel-plugin-named-asset-import^0.3.8
babel-preset-react-app^10.0.1
bfj^7.0.2
browserslist^4.18.1
camelcase^6.2.1
case-sensitive-paths-webpack-plugin^2.4.0
css-loader^6.5.1
css-minimizer-webpack-plugin^3.2.0
dotenv^10.0.0
dotenv-expand^5.1.0
eslint^8.3.0
eslint-config-react-app^7.0.1
eslint-webpack-plugin^3.1.1
file-loader^6.2.0
fs-extra^10.0.0
html-webpack-plugin^5.5.0
identity-obj-proxy^3.0.0
jest^27.4.3
jest-enzyme^7.1.2
jest-resolve^27.4.2
jest-watch-typeahead^1.0.0
mini-css-extract-plugin^2.4.5
postcss^8.4.4
postcss-flexbugs-fixes^5.0.2
postcss-loader^6.2.1
postcss-normalize^10.0.1
postcss-preset-env^7.0.1
prompts^2.4.2
react^18.2.0
react-app-polyfill^3.0.0
react-dev-utils^12.0.1
react-dom^18.2.0
react-refresh^0.11.0
resolve^1.20.0
resolve-url-loader^4.0.0
sass-loader^12.3.0
semver^7.3.5
source-map-loader^3.0.0
style-loader^3.3.1
tailwindcss^3.0.2
terser-webpack-plugin^5.2.5
web-vitals^2.1.4
webpack^5.64.4
webpack-dev-server^4.6.0
webpack-manifest-plugin^4.0.2
workbox-webpack-plugin^6.4.1"

具体配置、操作和内容会有差异,“坑”也会有所不同。。。


一、Jest 前端自动化测试框架基础入门

  • 一、Jest 前端自动化测试框架基础入门(一)

  • 一、Jest 前端自动化测试框架基础入门(二)

7.异步代码的测试方法

安装 axios

npm i axios@0.19.0 -S

新建 fetchData.js:

import axios from 'axios'export const fetchData = (fn) => {axios.get('http://www.dell-lee.com/react/api/demo.json').then(res => fn(res.data))
}

新建单元测试文件 fetchData.test.js:

import fetchData from './fetchData'// 回调类型异步函数的测试
test('fetchData 返回结果为 { success: true }', (done) => {fetchData((data) => {expect(data).toEqual({success: true})// 只有当 done 函数被执行到才认为是测试用例执行结束done();})
})

不使用 done 的话,测试用例执行到 fetchData 之后直接就返回 pass

还有一种情况,将 Promise 对象直接返回出来:修改 fetchData.js:

import axios from 'axios'export const fetchData = () => {return axios.get('http://www.dell-lee.com/react/api/demo.json')
}

相应修改单元测试文件 fetchData.test.js:

import fetchData from './fetchData'test('fetchData 返回结果为 Promise: { success: true }', () => {return fetchData().then((res) => {expect(res.data).toEqual({success: true})})
})

若是想要单独测试 404,可以修改为如下

import fetchData from './fetchData'test('fetchData 返回结果为 404', () => {expect.assertions(1) // 下面的 expect 至少执行一个return fetchData().catch((e) => {expect(e.toString().indexOf('404') > -1).toBe(true)})
})

若是不使用 expect.assertions ,当测试 接口访问成功,没走 catch 时,相当于啥也没有执行,也会通过,加上后若是接口访问成功会报错:Expected one assertion to be called but received zero assertion calls.

还有可以使用 expect 自带的函数识别结果:

test('fetchData 返回结果为 Promise: { success: true }', () => {return expect(fetchData()).resolves.toMatchObject({data: {success: true}})
})
test('fetchData 返回结果为 404', () => {return expect(fetchData()).rejects.toThrow()
})

除了使用 return 还可以使用 async…await 的语法:

test('fetchData 返回结果为 Promise: { success: true }', async () => {await expect(fetchData()).resolves.toMatchObject({data: {success: true}})
})
test('fetchData 返回结果为 404', async () => {await expect(fetchData()).rejects.toThrow()
})

还可以使用 async…await 先拿到响应结果,再判断:

test('fetchData 返回结果为 Promise: { success: true }', async () => {const res = await fetchData()expect(res.data).toEqual({success: true})
})
test('fetchData 返回结果为 404', async () => {expect.assertions(1) // 下面的 expect 至少执行一个try {await fetchData()} catch (e) {expect(e.toString()).toEqual('Error: Request failed with status code 404.')}
})

8.Jest 中的钩子函数

Jest 中的钩子函数指的是在 Jest 执行过程中到某一特定时刻被自动调用的函数,类似 Vue/React 中的生命周期函数

新建 Counter.js

export default class Counter {constructor() {this.number = 0}addOne() {this.number += 1}minusOne() {this.number -= 1}
}

新建 Counter.test.js

import Counter from "./Counter";describe('测试 Counter', () => {const counter = new Counter();test('测试 addOne 方法', () => {counter.addOne()expect(counter.number).toBe(1)})test('测试 minusOne 方法', () => {counter.minusOne()expect(counter.number).toBe(0)})
})

运行测试用例,直接通过,但是两个测试用例共用了一个实例 counter,相互之间有影响,这显然是不可以的,可以引入 Jest 的 钩子函数来做预处理

修改 Counter.test.js

import Counter from "./Counter";describe('测试 Counter', () => {let counter = nullbeforeAll(() => {console.log('beforeAll')})beforeEach(() => {console.log('beforeEach')counter = new Counter();})afterEach(() => {console.log('afterEach')// counter = null})afterAll(() => {console.log('afterAll')})test('测试 addOne 方法', () => {console.log('测试 addOne ')counter.addOne()expect(counter.number).toBe(1)})test('测试 minusOne 方法', () => {console.log('测试 minusOne ')counter.minusOne()expect(counter.number).toBe(-1)})
})

这样就不会相互之间产生影响了

编辑 Counter.js 新增两个方法

export default class Counter {constructor() {this.number = 0}addOne() {this.number += 1}addTwo() {this.number += 2}minusOne() {this.number -= 1}minusTwo() {this.number -= 2}
}

这时候测试文件怎么写呢?很显然功能有分类,可以使用 describe

编辑 Counter.test.js

import Counter from "./Counter";describe('测试 Counter', () => {let counter = nullbeforeAll(() => {console.log('beforeAll')})beforeEach(() => {console.log('beforeEach')counter = new Counter();})afterEach(() => {console.log('afterEach')// counter = null})afterAll(() => {console.log('afterAll')})describe('测试“增加”相关的方法', () => {test('测试 addOne 方法', () => {console.log('测试 addOne ')counter.addOne()expect(counter.number).toBe(1)})test('测试 addTwo 方法', () => {console.log('测试 addTwo ')counter.addTwo()expect(counter.number).toBe(2)})})describe('测试“减少”相关的方法', () => {test('测试 minusOne 方法', () => {console.log('测试 minusOne ')counter.minusOne()expect(counter.number).toBe(-1)})test('测试 minusTwo 方法', () => {console.log('测试 minusTwo ')counter.minusTwo()expect(counter.number).toBe(-2)})})
})

测试日志如下:

测试 Counter测试“增加”相关的方法√ 测试 addOne 方法 (6ms)√ 测试 addTwo 方法 (4ms)测试“减少”相关的方法√ 测试 minusOne 方法 (4ms)√ 测试 minusTwo 方法 (4ms)console.log Counter.test.js:8beforeAllconsole.log Counter.test.js:12beforeEachconsole.log Counter.test.js:27测试 addOneconsole.log Counter.test.js:17afterEachconsole.log Counter.test.js:12beforeEachconsole.log Counter.test.js:32测试 addTwoconsole.log Counter.test.js:17afterEachconsole.log Counter.test.js:12beforeEachconsole.log Counter.test.js:41测试 minusOneconsole.log Counter.test.js:17afterEachconsole.log Counter.test.js:12beforeEachconsole.log Counter.test.js:46测试 minusTwoconsole.log Counter.test.js:17afterEachconsole.log Counter.test.js:22afterAllTest Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        4.411s

9.钩子函数的作用域

每一个 describe 都可以有自己的 beforeAll、afterAll、beforeEach、afterEach,执行顺序是从外往内。

外部的钩子函数可以对当前 describe 所有的测试用例起作用,而内部的只对内部的测试用例起作用,这就是钩子函数的作用域。

可以自行编写尝试,这里就不再赘述了。

还有一个单元测试小技巧,test 使用 only 修饰符可以让单元测试只运行这一个测试用例:

test.only('', () => {})

注意,代码执行顺序中,最先执行的是不包含在任何测试用例和钩子函数中的语句(直接暴露在各个 describe 内部最外层的语句),且只执行一次,后续才是测试用例和钩子函数的执行。


本文仅作记录, 实战要点待后续专文总结,敬请期待。。。

相关文章:

【实战】一、Jest 前端自动化测试框架基础入门(三) —— 前端要学的测试课 从Jest入门到TDD BDD双实战(三)

文章目录 一、Jest 前端自动化测试框架基础入门7.异步代码的测试方法8.Jest 中的钩子函数9.钩子函数的作用域 学习内容来源:Jest入门到TDD/BDD双实战_前端要学的测试课 相对原教程,我在学习开始时(2023.08)采用的是当前最新版本&a…...

信息学奥赛一本通1228:书架

1228:书架 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 18190 通过数: 10557 【题目描述】 John最近买了一个书架用来存放奶牛养殖书籍,但书架很快被存满了,只剩最顶层有空余。 John共有N�头奶牛(1≤N≤20,0001≤…...

红队打靶练习:GLASGOW SMILE: 1.1

目录 信息收集 1、arp 2、nmap 3、nikto 4、whatweb 目录探测 1、gobuster 2、dirsearch WEB web信息收集 /how_to.txt /joomla CMS利用 1、爆破后台 2、登录 3、反弹shell 提权 系统信息收集 rob用户登录 abner用户 penguin用户 get root flag 信息收集…...

网络安全的今年:量子、生成人工智能以及 LLM 和密码

尽管世界总是难以预测,但网络安全的几个强劲趋势表明未来几个月的发展充满希望和令人担忧。有一点是肯定的:2024 年将是非常重要且有趣的一年。 近年来,人工智能(AI)以令人难以置信的速度发展,其在网络安全…...

【FPGA】Verilog:奇偶校验位发生器 | 奇偶校验位校验器

目录 0x00 奇偶校验位发生器 0x01 奇偶校验位校验器 0x02 错误检测器和纠错器...

【心得】关于STM32中RTC的校准方法

最近看了一些关于RTC校准的帖子,发现很多人存在疑惑。正好最近我也在STM32中实现了RTC校准。发些心得。这些对老手来说有些罗索,但对新手有益处。 实现RTC 校准的核心之一是库文件Stm321f0x_bkp.c中的void BKP_SetRTCCalibrationValue (uint8_t Calibra…...

消息中间件面试篇

目录 消息中间件 RabbitMQ 消息不丢失 生产者确认机制 消息持久化 交换机持久化 队列持久化 消息持久化 消费者确认 消息重复消费 出现的场景 解决方案 每条消息设置一个唯一的标识id 幂等方案:【 分布式锁、数据库锁(悲观锁、乐观锁&#…...

【MySQL】-20 MySQL综合-6(MySQL创建数据表+MySQL修改数据表+MySQL删除数据表)

MySQL创建数据表MySQL修改数据表MySQL删除数据表 MySQL创建数据表基本语法在指定的数据库中创建表查看表结构 MySQL修改数据表基本语法添加字段修改字段数据类型删除字段修改字段名称修改表名 MySQL删除数据表基本语法删除表 MySQL创建数据表 在创建数据库之后,接下…...

linux查看当前连接的IP

linux下查询当前所有连接的ip_linux查看某个ip的连接-CSDN博客 netstat -ntu | grep tcp | awk {print $5} | cut -d: -f1 | sort | uniq -c | sort -nr...

洛谷_P1923 【深基9.例4】求第 k 小的数_python写法

哪位大佬可以出一下这个的题解?????话说蓝桥杯可以用numpy库吗?????? 这道题有一个很简单的思路就是排序完成之后再访问。 but有很大的问题&…...

【MySQL】学习约束和使用图形化界面创建表

🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​💫个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-iqtbME2KmWpQFQSt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…...

QGIS编译(跨平台编译)之四十八:pixman编译(Windows、Linux、MacOS环境下编译)

文章目录 一、pixman介绍二、pixman下载三、Linux下编译四、MacOS下编译五、Windows下编译一、pixman介绍 Pixman 是一个开源的图形库,它提供了底层像素操作功能,包括像素格式转换、图像合成、图像缩放、图像旋转等多种操作。Pixman 主要被用作 Cairo 图形库的后端,支持 Ca…...

华为数通方向HCIP-DataCom H12-821题库(单选题:441-460)

第441题 下面是一台路由输出的信息,关于这段信息描述正确的是 <R1>display bgp peerBGP local router ID : 2.2.2.2Local AS number : 100Total number of peers : 2 Peers in established state : 0Peer V AS MsgRcvd MsgSent OutQ Up/Down …...

【sass】 中使用 /deep/ 修改 elementUI 组件样式报错

element plus 想要覆盖组件的样式&#xff0c;想到了/deep/样式穿透&#xff0c;但样式一直不生效&#xff0c;代码如下&#xff1a; <style scoped lang"sass"> .main_wrapper{padding: 0 53pxposition: relativetop: -20px } >>> .el-tabs__item{h…...

Python算法题集_排序链表

Python算法题集_排序链表 题148&#xff1a;排序链表1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【冒泡大法】2) 改进版一【列表排序】3) 改进版二【数值归并排序】4) 改进版三【快慢指针归并排序】 4. 最优算法 本文为Python算法题集之一的…...

红日靶场2学习

靶场下载来自&#xff1a; http://vulnstack.qiyuanxuetang.net/vuln/detail/3/ 靶场统一登录密码&#xff1a;1qazWSX 按大佬的说法是 环境需要模拟内网和外网两个网段&#xff0c;PC端虚拟机相当于网关服务器&#xff0c;所以需要两张网卡&#xff0c;一个用来向外网提供web…...

将 下载下来的 jar 包 安装到本地的 maven 仓库中

使用管理员权限 打开一个 cmd 窗口输入 mvn -v 查看 maven 版本由于之前 并没有这样的操作所以第一次 执行的时候 提示 命令不存在所以需要将 maven 软件中的 bin 文件的目录 添加到 环境变量中 的 path 变量 中本机路径为:D:\Program Files (x86)\apache-maven-3.5.2\bin C:\…...

Qt初使用(使用Qt创建项目,在创建的项目中添加类,Qt中输出内容到控制台,设置窗口大小和窗口标题,Qt查看说明文档)

目录 一.创建带模板的项目新建项目运行在文件中查看该项目文件 二.在创建好的项目中添加类三.创建空项目&#xff08;不使用自带的模板&#xff09;四.Qt中输出内容到控制台五.设置窗口大小 , 窗口标题 ,固定窗口大小QWidget组件的说明 六.Pro文件帮助文档 按windows键&#xf…...

【黑马程序员】C++运算符重载

文章目录 运算符重载加号运算符重载成员函数实现运算符重载全局函数实现运算符重载全局函数实现函数重载 左移运算符重载递增运算符重载赋值运算符重载关系运算符重载函数调用运算符重载 运算符重载 对已有的运算符重新进行定义&#xff0c;赋予其另一种功能&#xff0c;以适应…...

Java中的乐观锁和悲观锁

使用场景及用法 悲观锁 总是假设最坏的情况&#xff0c;每次去拿数据的时候都认为别人会修改&#xff0c;所以每次在拿数据的时候都会上锁&#xff0c;这样别人想拿这个数据就会阻塞直到它拿到锁&#xff08;共享资源每次只给一个线程使用&#xff0c;其它线程阻塞&#xff0c;…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行

项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战&#xff0c;克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

django blank 与 null的区别

1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是&#xff0c;要注意以下几点&#xff1a; Django的表单验证与null无关&#xff1a;null参数控制的是数据库层面字段是否可以为NULL&#xff0c;而blank参数控制的是Django表单验证时字…...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...