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

本文主要是介绍【实战】一、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双实战(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/709315

相关文章

RedHat运维-Linux文本操作基础-AWK进阶

你不用整理,跟着敲一遍,有个印象,然后把它保存到本地,以后要用再去看,如果有了新东西,你自个再添加。这是我参考牛客上的shell编程专项题,只不过换成了问答的方式而已。不用背,就算是我自己亲自敲,我现在好多也记不住。 1. 输出nowcoder.txt文件第5行的内容 2. 输出nowcoder.txt文件第6行的内容 3. 输出nowcoder.txt文件第7行的内容 4. 输出nowcode

Vim使用基础篇

本文内容大部分来自 vimtutor,自带的教程的总结。在终端输入vimtutor 即可进入教程。 先总结一下,然后再分别介绍正常模式,插入模式,和可视模式三种模式下的命令。 目录 看完以后的汇总 1.正常模式(Normal模式) 1.移动光标 2.删除 3.【:】输入符 4.撤销 5.替换 6.重复命令【. ; ,】 7.复制粘贴 8.缩进 2.插入模式 INSERT

C++必修:模版的入门到实践

✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C++学习 贝蒂的主页:Betty’s blog 1. 泛型编程 首先让我们来思考一个问题,如何实现一个交换函数? void swap(int& x, int& y){int tmp = x;x = y;y = tmp;} 相信大家很快就能写出上面这段代码,但是如果要求这个交换函数支持字符型

零基础STM32单片机编程入门(一)初识STM32单片机

文章目录 一.概要二.单片机型号命名规则三.STM32F103系统架构四.STM32F103C8T6单片机启动流程五.STM32F103C8T6单片机主要外设资源六.编程过程中芯片数据手册的作用1.单片机外设资源情况2.STM32单片机内部框图3.STM32单片机管脚图4.STM32单片机每个管脚可配功能5.单片机功耗数据6.FALSH编程时间,擦写次数7.I/O高低电平电压表格8.外设接口

vue, 左右布局宽,可拖动改变

1:建立一个draggableMixin.js  混入的方式使用 2:代码如下draggableMixin.js  export default {data() {return {leftWidth: 330,isDragging: false,startX: 0,startWidth: 0,};},methods: {startDragging(e) {this.isDragging = tr

ps基础入门

1.基础      1.1新建文件      1.2创建指定形状      1.4移动工具          1.41移动画布中的任意元素          1.42移动画布          1.43修改画布大小          1.44修改图像大小      1.5框选工具      1.6矩形工具      1.7图层          1.71图层颜色修改          1

C++入门01

1、.h和.cpp 源文件 (.cpp)源文件是C++程序的实际实现代码文件,其中包含了具体的函数和类的定义、实现以及其他相关的代码。主要特点如下:实现代码: 源文件中包含了函数、类的具体实现代码,用于实现程序的功能。编译单元: 源文件通常是一个编译单元,即单独编译的基本单位。每个源文件都会经过编译器的处理,生成对应的目标文件。包含头文件: 源文件可以通过#include指令引入头文件,以使

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主

React+TS前台项目实战(十七)-- 全局常用组件Dropdown封装

文章目录 前言Dropdown组件1. 功能分析2. 代码+详细注释3. 使用方式4. 效果展示 总结 前言 今天这篇主要讲全局Dropdown组件封装,可根据UI设计师要求自定义修改。 Dropdown组件 1. 功能分析 (1)通过position属性,可以控制下拉选项的位置 (2)通过传入width属性, 可以自定义下拉选项的宽度 (3)通过传入classN

js+css二级导航

效果 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Con