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

文章目录

    • 一、Jest 前端自动化测试框架基础入门
      • 10.Jest 中的 Mock
        • (1)toBeCalled
        • (2)func.mock
        • (3)mockReturnValue & mockReturnValueOnce


学习内容来源: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 前端自动化测试框架基础入门(二)

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

10.Jest 中的 Mock

新建 lesson8.js

export const runCallback = callback => {callback();
}

要测试 runCallback 一般思路都是创建一个函数,返回一个值,只要 expect 最终拿到这个值就说明没问题,但是 runCallback 的主要功能是执行 callback,若是和本示例这样没有将 callback 返回,岂不是测不了了。。。

因此最佳实践来了,如下。

(1)toBeCalled

新建 lesson8.test.js

import { runCallback } from "./lesson8";test('测试 runCallback', () => {const func = jest.fn();runCallback(func);expect(func).toBeCalled();  
})

mock 一个函数,使用 toBeCalled 即可检测函数是否被调用

(2)func.mock

打印看一下 func.mock 里面有啥(console.log(func.mock)):

{calls: [ [] ],instances: [ undefined ],invocationCallOrder: [ 1 ],results: [ { type: 'return', value: undefined } ]
}
  • calls:func 每次执行的入参列表的列表
  • instances:每次执行 func 时创建的实例的列表(即 函数中this的指向,默认 undefined)
  • invocationCallOrder:每次 func 执行的顺序列表(例如:1, 2, 3 表示按顺序执行)
  • results:每次执行 func 的返回值列表

编辑 lesson8.test.js(执行两次 func)

import { runCallback } from "./lesson8";test('测试 runCallback', () => {const func = jest.fn();runCallback(func);runCallback(func);expect(func).toBeCalled();  console.log(func.mock)
})

再看一下 func.mock 里面有啥:

{calls: [ [], [] ],instances: [ undefined, undefined ],invocationCallOrder: [ 1, 2 ],results: [{ type: 'return', value: undefined },{ type: 'return', value: undefined }]
}

可以看到每一次调用在 func.mock 中都是留有痕迹的

编辑 lesson8.test.js(给 func 传入一个函数,并执行三次)

test('测试 runCallback', () => {const func = jest.fn(() => 123); // mock 函数,捕获函数的调用// func.mockImplementation(() => 123); // 功能同上一句// func.mockImplementationOnce(() => 123); // 只模拟一次// func.mockImplementationOnce(() => 456); // 只模拟一次// func.mockImplementation(() => this);// func.mockReturnThis(); // 作用同上一句runCallback(func);runCallback(func);runCallback(func);expect(func).toBeCalled();// expect(func).toBeCalledWith(); // 断言每次调用的入参内容console.log(func.mock)
})

打印结果:

{calls: [ [], [], [] ],instances: [ undefined, undefined, undefined ],invocationCallOrder: [ 1, 2, 3 ],results: [{ type: 'return', value: 123 },{ type: 'return', value: 123 },{ type: 'return', value: 123 }]
}

注意:带 Once 的要优先于不带的执行

(3)mockReturnValue & mockReturnValueOnce

编辑 lesson8.test.js(让 func 通过 mockReturnValueOnce 来返回值)

test('测试 runCallback', () => {const func = jest.fn(); // mock 函数,捕获函数的调用func.mockReturnValueOnce('once')runCallback(func);runCallback(func);runCallback(func);expect(func).toBeCalled();console.log(func.mock)
})

打印结果:

{calls: [ [], [], [] ],instances: [ undefined, undefined, undefined ],invocationCallOrder: [ 1, 2, 3 ],results: [{ type: 'return', value: 'once' },{ type: 'return', value: undefined },{ type: 'return', value: undefined }]
}

可以看到 'once' 只返回了一次

编辑 lesson8.test.js(让 func 通过 mockReturnValueOnce, mockReturnValueOnce 链式调用,mockReturnValue 三种方式来返回值)

test('测试 runCallback', () => {const func = jest.fn(); // mock 函数,捕获函数的调用func.mockReturnValueOnce('1');func.mockReturnValueOnce('2');func.mockReturnValueOnce('3').mockReturnValueOnce('4').mockReturnValueOnce('5');func.mockReturnValue('6'); // 后续每次返回同样的值[...new Array(8)].map(() => runCallback(func))expect(func).toBeCalled();console.log(func.mock)
})

打印结果:

{calls: [[], [], [], [],[], [], [], []],instances: [undefined, undefined,undefined, undefined,undefined, undefined,undefined, undefined],invocationCallOrder: [1, 2, 3, 4,5, 6, 7, 8],results: [{ type: 'return', value: '1' },{ type: 'return', value: '2' },{ type: 'return', value: '3' },{ type: 'return', value: '4' },{ type: 'return', value: '5' },{ type: 'return', value: '6' },{ type: 'return', value: '6' },{ type: 'return', value: '6' }]
}

接下来通过示例理解一下 mock 里的 instances

编辑 lesson8.js(callback 运行一次,之后创建一个实例,并赋予一个属性作为标识)

export const runCallback = (callback, index) => {callback();let obj = new callback()obj.name = 'callback_' + index
}

编辑 lesson8.test.js

test('测试 runCallback', () => {const func = jest.fn(); // mock 函数,捕获函数的调用func.mockReturnValue('6');  // 后续每次返回同样的值[...new Array(3)].map((item, index) => runCallback(func, index))expect(func).toBeCalled();console.log(func.mock)
})

打印结果:

{calls: [ [], [], [], [], [], [] ],instances: [undefined,mockConstructor { name: 'callback_0' },undefined,mockConstructor { name: 'callback_1' },undefined,mockConstructor { name: 'callback_2' }],invocationCallOrder: [ 1, 2, 3, 4, 5, 6 ],results: [{ type: 'return', value: '6' },{ type: 'return', value: undefined },{ type: 'return', value: '6' },{ type: 'return', value: undefined },{ type: 'return', value: '6' },{ type: 'return', value: undefined }]
}

可见每次运行默认不会有实例化对象,因此是 undefined,但是在实例化后,就会有一个命名为 mockConstructor 的构造对象

普通函数可以通过 jest.fn() 的方式来 mock,为保证当前部分功能的独立性,那接口请求也是需要 mock 的(避免网络和后端的影响)

编辑 lesson8.js(新增 getData 请求接口)

export const getData = () => {return axios.get('/api').then(res => res.data)
}

编辑 lesson8.test.js

import { runCallback, getData } from "./lesson8";
import axios from 'axios'jest.mock('axios');...test.only('测试 getData', async () => {axios.get.mockResolvedValue({data: 'hello'})await getData().then(data => {expect(data).toBe('hello')})
})

注意:jest.mock 必须放在文件的上面紧贴着 import,且外面不能嵌套任何内容否则对其mock的内容的作用域有影响(与被mock内容保持一致,且加载顺序挨着)

总结一下 mock 的几大功能:

  1. 捕获函数的调用和返回结果,以及 this 和调用顺序
  2. 可以自由设置返回结果
  3. 改变函数的内部实现

注意,从25版本开始,官方文档的结构发生了一些变化,最后一个变化前的版本:

  • https://archive.jestjs.io/docs/en/24.x/api

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/683496.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法训练day29Leetcode491递增子序列46全排列47全排列Ⅱ

491 递增子序列 题目描述 给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。 数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一…

【自我介绍】计算机软件工程人工智能研究生复试资料整理

1、JAVA 2、计算机网络 3、计算机体系结构 4、数据库 5、计算机租场原理 6、软件工程 7、大数据 8、英文 自我介绍 自我介绍 英文 自我介绍 英文 第一段: Good afternoon, dear professors, thank you for the chance to introduce myself. My name is Yan Zhen Xing, and I a…

已解决AttributeError: ‘str‘ object has no attribute ‘decode‘异常的正确解决方法,亲测有效!!!

已解决AttributeError: str object has no attribute decode异常的正确解决方法,亲测有效!!! 文章目录 问题分析 报错原因 解决思路 解决方法 总结 当你在Python编程时碰到“AttributeError: str object has no attribute d…

UVA1449 Dominating Patterns 题解

UVA1449 Dominating Patterns 题解 板子题诶。 解法 AC 自动机模板题,因为数据范围比较小,所以不加拓扑排序优化建图即可通过本题。这里简单介绍一下拓扑排序优化建图。 在查找时,每次都暴力的条 f a i l fail fail 指针是很消耗时间的&…

vue-进阶语法(四)

目录 v-model原理 v-model应用于组件 sync修饰符 ref 和 $refs(重点) $nextTick v-model原理 原理:v-model本质上是一个语法糖。例如应用在输入框上,就是 value属性 和 input事件 的合写。 作用:提供数据的双向…

压缩PDF的大小-Adobe Acrobat Pro

经常遇到上传的pdf太大,无法成功上传。 今天找到一个方法: 打开Adobe Acrobat Pro软件 → 文件 → 另存为其他(H)... →缩小大小的PDF 版本选择 4.0 最低的版本。 文件由9M变为1.5M。

Codeforces Round 924 (Div. 2) B - D

B. Equalize 题目: 思路:首先排序然后去重(可以用set来去重),我们可以肯定的是,如果连续k个数最大值最小值的差小于等于n的话,那么这个长度为k的区间就符合答案要求,那么k就和答案…

###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯

前言:感谢您的关注哦,我会持续更新编程相关知识,愿您在这里有所收获。如果有任何问题,欢迎沟通交流!期待与您在学习编程的道路上共同进步。 目录 一. 延时函数的生成 1.通过延时计算器得到延时函数 2.可赋值改变…

Linux释放内存

free -m是Linux上查看内存的指令,其中-m是以兆(MB)为单位,如果不加则以KB为单位。 如下图表示,(total)总物理内存是809MB,(used)已使用167MB,&…

【AI视野·今日NLP 自然语言处理论文速览 第七十九期】Thu, 18 Jan 2024

AI视野今日CS.NLP 自然语言处理论文速览 Thu, 18 Jan 2024 Totally 35 papers 👉上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Deciphering Textual Authenticity: A Generalized Strategy through the Lens of Large Language Semantics …

使用STM32CubeMX配置和优化DMA传输

STM32CubeMX是STMicroelectronics提供的一款图形化配置工具,可以帮助开发人员对STM32微控制器进行初始化配置和代码生成。在本文中,我们将介绍如何使用STM32CubeMX来配置和优化DMA传输,并提供一个简单的示例代码来演示DMA的配置和使用。 ✅作…

【Py/Java/C++三种语言详解】LeetCode每日一题240215【二叉树BFS】LeetCode107、二叉树的层序遍历II

有LeetCode交流群/华为OD考试扣扣交流群可加:948025485 可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题 绿色聊天软件戳 od1336了解算法冲刺训练 文章目录 题目链接题目描述解题思路DFS和BFS异同用队列维护的BFS 代码PythonJavaC时空复杂度 相关习题华为OD算法/大…

寒假学习记录13:JS对象

目录 对象转数组 对象双值转数组 Object.entries() (转为二维数组)(属性的值和键) 对象右值转数组 Object.values() (属性的值) 对象左值转数组 Object.keys() (属性的键) 对象左值转…

计算机视觉基础:获取图像的ROI

在图像处理过程中,我们可能会对图像的某一个特定区域感兴趣,该区域被称为感兴趣区域(Region of Interest,ROI)。在设定感兴趣区域ROI后,就可以对该区域进行整体操作。 Python实现代码如下: # -…

怎样学习Windows下命令行编写

第一:Windows下命令行指的是cmd和powershell命令行编写 第二:必须要用好help或/?命令,这个命令是最基本的也是最常用的命令列表和语法查看命令 第三:cmd命令使用help查看命令列表或“一串带参数的命令 /?"(不…

[职场] 花园管家是做什么的 #笔记#学习方法

花园管家是做什么的 一、工作内容职责: 1.管理花园内的活动和工作,协调各方资源,确保活动的顺利进行; 2.提供优质的客户服务和接待工作,解决客户问题,处理投诉,提高客户满意度; …

(03)Hive的相关概念——分区表、分桶表

目录 一、Hive分区表 1.1 分区表的概念 1.2 分区表的创建 1.3 分区表数据加载及查询 1.3.1 静态分区 1.3.2 动态分区 1.4 分区表的本质及使用 1.5 分区表的注意事项 1.6 多重分区表 二、Hive分桶表 2.1 分桶表的概念 2.2 分桶表的创建 2.3 分桶表的数据加载 2.4 …

C++ 基础算法 前缀和

输入一个长度为 n 的整数序列。 接下来再输入 m 个询问,每个询问输入一对 l,r 。 对于每个询问,输出原序列中从第 l 个数到第 r 个数的和。 输入格式 第一行包含两个整数 n 和 m 。 第二行包含 n 个整数,表示整数数列。 接下来 m 行&…

操作系统(14)----文件系统的结构

目录 一.文件系统的层次结构 1.用户接口: 2.文件目录系统: 3.存取控制模块: 4.逻辑文件系统与文件信息缓冲区: 5.物理文件系统: 二.文件系统的全局结构 1.文件系统在外存中的结构 (1)物…

Mermaid绘制UML图教程

Mermaid 是一种轻量级的图形描述语言,用于绘制流程图、时序图、甘特图等各种图表。它采用简单的文本语法,使得用户能够快速绘制各种复杂图表,而无需深入学习图形绘制工具。 一、安装Mermaid Mermaid 可以在浏览器中直接使用,也可…