全面掌握 Jest:从零开始的测试指南(上篇)
随着JavaScript在前后端开发中的广泛应用,测试已成为保证代码质量的关键环节。
为什么需要单元测试
在我们的开发过程中,经常需要定义一些算法函数,例如将接口返回的数据转换成UI组件所需的格式。为了校验这些算法函数的健壮性,部分开发同学可能会手动定义几个输入样本进行初步校验,一旦校验通过便不再深究。
然而,这样的做法可能会带来一些潜在的问题。首先,边界值的情况往往容易被忽视,导致校验不够全面,增加了系统出现故障的风险。其次,随着需求的变化和演进,算法函数可能需要进行优化和扩展。如果前期的校验工作不够彻底,不了解现有函数覆盖的具体场景,就可能导致在后续的修改中引入新的问题。
单元测试可以有效地解决上述问题。在定义算法函数时,同步创建单元测试文件,并将可能出现的各种场景逐一列举。如果单元测试未能通过,项目在编译时会直接报错,从而能够及时发现并针对性地解决问题。此外,当后续有新同学加入并需要扩展功能时,他们不仅需要在原有的单元测试基础上添加新的测试用例,还能确保新功能的正确性,同时保障原有功能的正常运行。
自定义测试逻辑
在开始使用工具来进行单元测试之前,我们可以先自定义一个工具函数供测试使用。
例如,我们有一个 add
函数,期望它能够正确计算两个数的和,并验证其结果是否符合预期。比如,我们希望验证 2 + 3
的结果是否等于 5
,可以使用 expect(add(2, 3)).toBe(5)
这样的代码来实现。为此,我们可以自行定义一个expect
函数,使其具备类似Jest中 expect
函数的功能
function add(a, b) { return a + b; }
function expect(result) {return {toBe(value) {if (result === value) {console.log("验证成功");} else {throw new Error(`执行错误:${result} !== ${value}`);}},};
}// 调用示例
try {expect(add(2, 3)).toBe(5); // 输出:"验证成功"expect(add(2, 3)).toBe(6); // 抛出错误
} catch (err) {console.error(err.message); // 输出:"执行错误:5 !== 6"
}
为了使测试更具描述性和可读性,我们可以进一步增强我们的测试逻辑。例如,我们可以添加一个 test
函数,用于描述测试的目的,并在测试失败时提供更详细的错误信息。
function test(description, fn) {try {fn();console.log(`测试通过: ${description}`);} catch (err) {console.error(`测试失败: ${description} - ${err.message}`);}
}
// 调用示例
test("验证 2 + 3 是否等于 5", () => {expect(add(2, 3)).toBe(5);
});
test("验证 2 + 3 是否等于 6", () => {expect(add(2, 3)).toBe(6);
});
通过这种方式,我们模拟了一个简单的测试用例,其中 test
和 expect
函数类似于Jest中的功能。然而,我们的自定义版本相对简陋,缺乏 Jest
提供的丰富功能。
Jest
通过上述示例,我们可以了解到编写测试的基本思路和方法。然而,在实际开发中,我们需要一个功能更加强大、易用性更高的测试工具。Jest
正是这样一个工具,它不仅提供了丰富的匹配器
(如toBe、toEqual等),还支持异步测试
、Mock函数
、Snapshot测试
等功能。
引入 Jest
的依赖后,我们可以直接使用其内置的 test
和 expect
函数,从而大大提高测试的效率和准确性。Jest
的强大之处在于它能够帮助我们全面地覆盖各种测试场景,并提供详细的错误报告,使我们能够快速定位和解决问题。
初始化
首先,我们通过 npm install jest -D
安装 Jest
依赖,然后执行 npx jest --init
。此时,命令行工具会出现一系列交互式问答,询问你是否要为 Jest 添加名为 test 的脚本指令、是否使用 TypeScript 作为配置文件、测试用例执行环境、是否需要代码覆盖率测试报告、生成测试报告的平台的编译器以及是否需要在每次测试用例执行前重置 Mock 函数状态。
完成所有问答后,Jest 会修改 package.json
文件,并生成jest.config.js
配置文件。在执行测试用例时,将依据这些配置项进行。
我们创建一个 math.test.js
文件,并将之前的测试代码放入其中
function add(a, b) {return a + b;
}
test("测试 add 函数", () => {expect(add(2, 3)).toBe(5);
});
通过 npm run test
执行 Jest 运行指令,可以在命令行工具查看详细的测试信息,包括哪个文件的哪条测试用例的状态,以及简易的测试覆盖率报告。
在实际使用场景中,add
函数通常定义在项目文件中,并通过ES 模块化
(export 和 import) 方式导出和导入。默认情况下,Jest 并不支持 ES 模块化语法,因此我们需要通过 Babel 进行配置。
首先,执行以下命令安装 Babel 及其核心库和预设
npm install @babel/core @babel/preset-env --save-dev
然后,创建babel.config.js
文件并定义配置
module.exports = {presets: [["@babel/preset-env",{targets: {node: "current",},},],],
};
接着,将 add
函数移到 math.js
文件中,并使用 export
导出
// math.js
export function add(a, b) {return a + b;
}
最后,在 math.test.js 文件中使用 import 导入
// math.test.js
import { add } from './math';
test("测试 add 函数", () => {expect(add(2, 3)).toBe(5);
});
通过以上步骤,你就完成了使用 Jest 执行 ES 模块化代码的环境初始化。
匹配器
Jest 中最常用的功能之一就是匹配器。在前面进行测试时,我们就接触过 toBe
这一匹配器,它用于判断值是否相等。除此之外,还有许多其他类型的匹配器。
值相等
判断值相等有两种匹配器:toBe
和 toEqual
。对于基本数据类型(如字符串、数字、布尔值),两者的使用效果相同。但对于引用类型(如对象和数组),toBe
只有在两个引用指向同一个内存地址时才会返回 true
。
const user = { name: "alice" };
const info = { name: "alice" };test("toEqual", () => {expect(info).toEqual(user); // 通过,两者结构相同
});
test("toBe", () => {expect(info).toBe(user); // 不通过,两者的引用地址不同
});
是否有值
存在 toBeNull
、toBeUndefined
和 toBeDefined
匹配器来分别判断值是否为 null、未定义或已定义。
test("toBeNull", () => {expect(null).toBeNull();expect(0).toBeNull(); // 不通过expect("hello").toBeNull(); // 不通过expect(undefined).toBeBull(); // 不通过
});test("toBeUnDefined", () => {expect(null).toBeUndefined(); // 不通过expect(0).toBeUndefined(); // 不通过expect("hello").toBeUndefined(); // 不通过expect(undefined).toBeUndefined();
});test("toBeDefined", () => {expect(null).toBeDefined();expect(0).toBeDefined();expect("hello").toBeDefined();expect(undefined).toBeDefined(); // 不通过
});
是否为真
toBeTruthy
用于判断值是否为真,toBeFalsy
用于判断值是否为假,not
用于取反。
test("toBeTruthy", () => {expect(null).toBeTruthy(); // 不通过expect(0).toBeTruthy(); // 不通过expect(1).toBeTruthy();expect("").toBeTruthy(); // 不通过expect("hello").toBeTruthy();expect(undefined).toBeTruthy(); // 不通过
});
test("toBeFalsy", () => {expect(null).toBeFalsy();expect(0).toBeFalsy();expect(1).toBeFalsy(); // 不通过expect("").toBeFalsy();expect("hello").toBeFalsy(); // 不通过expect(undefined).toBeFalsy();
});
test("not", () => {expect(null).not.toBeTruthy();expect("hello").not.toBeTruthy(); // 不通过
});
数字比较
toBeGreaterThan
用于判断是否大于某个数值,toBeLessThan
用于判断是否小于某个数值,toBeGreaterThanOrEqual
用于判断是否大于或等于某个数值,toBeCloseTo
用于判断是否接近某个数值(差值 < 0.005)。
test("toBeGreaterThan", () => {expect(9).toBeGreaterThan(5);expect(5).toBeGreaterThan(5); // 不通过expect(1).toBeGreaterThan(5); // 不通过
});test("toBeLessThan", () => {expect(9).toBeLessThan(5); // 不通过expect(5).toBeLessThan(5); // 不通过expect(1).toBeLessThan(5);
});test("toBeGreaterThanOrEqual", () => {expect(9).toBeGreaterThanOrEqual(5);expect(5).toBeGreaterThanOrEqual(5);expect(1).toBeGreaterThanOrEqual(5); // 不通过
});test("toBeCloseTo", () => {expect(0.1 + 0.2).toBeCloseTo(0.3);expect(1 + 2).toBeCloseTo(3);expect(0.1 + 0.2).toBeCloseTo(0.4); // 不通过
});
字符串相关
toMatch
用于判断字符串是否包含指定子字符串,部分包含即可。
test("toMatch", () => {expect("alice").toMatch("alice"); // 通过expect("alice").toMatch("lice"); // 通过expect("alice").toMatch("al"); // 通过
});
数组相关
toContain
用于判断数组是否包含指定元素,类似于 JavaScript 中的 includes
方法。
test("toContain", () => {expect(['banana', 'apple', 'orange']).toContain("apple");expect(['banana', 'apple', 'orange']).toContain("app"); // 不通过
});
error相关
toThrow
用于判断函数是否抛出异常,并可以指定抛出异常的具体内容。
test("toThrow", () => {const throwNewErrorFunc = () => {throw new TypeError("this is a new error");};expect(throwNewErrorFunc).toThrow();expect(throwNewErrorFunc).toThrow("new error");expect(throwNewErrorFunc).toThrow("TypeError"); // 不通过
});
以上就是各类型常用的匹配器。
命令行工具
在 package.json
中配置 script
指令,可以使 .test.js
文件在修改时实时自动执行测试用例。
"scripts": {"jest": "jest --watchAll"
},
在命令行中,你会实时看到当前测试用例的执行结果。同时,Jest 还提供了一些快捷配置,按下 w
键即可查看具体有哪些指令。
主要有以下几种类型:
f 模式在所有测试用例中,只执行上一次失败的测试用例。即使其他测试用例的内容有修改,也不会被执行。
o 模式只执行修改过的测试用例。这个功能需要配合 Git
来实现,根据本次相对于上次 Git 仓库的更改。这种模式还可以通过配置 script 指令来实现,即:
"script": {
"test": "jest --watch"
}
p模式当使用--watchAll
时,修改一个文件的代码后,所有的测试用例都会执行。进入 p
模式后,可以输入文件名 matchersFile
,此时修改任何文件只会去查找包含 matchersFile
的文件并执行。
t模式输入测试用例名称,匹配 test 函数的第一个参数。匹配成功后即执行该测试用例。
q模式退出实时代码检测。
通过不同的指令,你可以更有针对性地检测测试用例。
钩子函数
在 Jest 中,describe 函数用于将一系列相关的测试用例(tests)组合在一起,形成一个描述性的测试块。它接受两个参数:第一个参数是一个字符串,用于描述测试块的主题;第二个参数是一个函数,包含一组测试用例。
即使没有显式定义 describe 函数,每个测试文件也会在最外层默认加上一层 describe 包裹。
在 describe 组成的每个块中,存在一些钩子函数,贯穿测试用例的整个过程。这些钩子函数主要用于测试用例执行之前的准备工作或之后的清理工作。
常用的钩子函数
-
beforeAll 函数在一个 describe 块开始之前执行一次
-
afterAll 函数在一个 describe 块结束之后执行一次
-
beforeEach 函数在每个测试用例之前执行
-
afterEach 在每个测试用例之后执行
示例代码
下面的示例代码展示了如何使用这些钩子函数:
describe("测试是否有值", () => {beforeAll(() => {console.log("beforeAll");});afterAll(() => {console.log("afterAll");});beforeEach(() => {console.log("beforeEach");});describe("toBeNull", () => {beforeAll(() => {console.log("toBeNull beforeAll");});afterAll(() => {console.log("toBeNull afterAll");});beforeEach(() => {console.log("toBeNull beforeEach");});test("toBeNull", () => {expect(null).toBeNull();});});
});
输出顺序
当运行上述测试用例时,输出的顺序如下:
beforeAll
toBeNull beforeAll
beforeEach
toBeNull beforeEach
toBeNull afterAll
afterAll
通过使用这些钩子函数,你可以更好地管理测试用例的生命周期,确保每次测试都从一个干净的状态开始,并在测试结束后清理掉产生的副作用。
在这一篇测试指南中,我们介绍了Jest 的背景、如何初始化项目、常用的匹配器语法、钩子函数。下一篇篇将继续深入探讨 Jest 的高级特性,包括 Mock 函数、异步请求的处理、Mock 请求的模拟、类的模拟以及定时器的模拟、snapshot 的使用。通过这些技术,我们将能够更高效地编写和维护测试用例,尤其是在处理复杂异步逻辑和外部依赖时。
文章转载自:一颗冰淇淋
原文链接:https://www.cnblogs.com/vigourice/p/18416692
体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构
相关文章:

全面掌握 Jest:从零开始的测试指南(上篇)
随着JavaScript在前后端开发中的广泛应用,测试已成为保证代码质量的关键环节。 为什么需要单元测试 在我们的开发过程中,经常需要定义一些算法函数,例如将接口返回的数据转换成UI组件所需的格式。为了校验这些算法函数的健壮性,部…...
Go 交叉编译
Mac 下编译 Linux 和 Windows 64位可执行程序 Linux: CGO_ENABLED0 GOOSlinux GOARCHamd64 go build main.go Windows: CGO_ENABLED0 GOOSwindows GOARCHamd64 go build main.go Linux 下编译 Mac 和 Windows 64位可执行程序 Mac: CGO_ENABLED0 G…...
goctl安装失败
今天遇到一个很奇怪的问题 在阿里云的ubuntu服务器上远程安装goctl:go install github.com/zeromicro/go-zero/tools/goctllatest,后面会断开ssh连接,就再也连不上了,connecting with ssh timed out。在阿里云的workbench上连接显…...

DebateGPT:通过多智能体辩论监督微调大模型
人工智能咨询培训老师叶梓 转载标明出处 这些模型的训练通常依赖于资源密集型的人工反馈,这不仅成本高昂,而且耗时。为了解决这一问题,一篇名为《FINE-TUNING LARGE LANGUAGE MODELS WITH MULTI-AGENT DEBATE SUPERVISION》的论文提出了一种…...

【最新综述】基于深度学习的超声自动无损检测(下)
4.Levels of automation 5.Basic axioms for DL-based ultrasonic NDE 在回顾了最新技术和每个自动化级别的贡献之后,我们不难发现,目前的数字语言方法论在不同论文之间存在着很大的差异。例如,有些作者提出了同时处理不同步骤的模型[121]&…...

kali——tshark的使用
目录 前言 使用方法 tshark提取流量为文档 前言 tshark 是一个命令行的网络分析工具,它用于捕获和分析网络流量。它支持多种网络协议,包括 TCP、UDP、ICMP 等。Tshark 可以用于调试网络问题、进行安全审计、分析应用程序性能等。 在 Kali Linux 中&…...

TortoiseSVN图标不显示的解决
解决办法一:修改svn软件的图标设置 1、选中一个文件夹或在桌面空白处,右击进入svn的setting 2、进入setting->Icon Overlays,Status cache选择Default或shell,然后点击应用 3、查看文件,图标可以正常显示 解决办法二:修改注册表的文件夹顺序 问题现象: 1、svn一直…...

Oracle 11gR2打PSU补丁详细教程
1 说明 Oracle的PSU(Patch Set Update)补丁是Oracle公司为了其数据库产品定期发布的更新包,通常每季度发布一次。PSU包含了该季度内收集的一系列安全更新(CPU:Critical Patch Update)以及一些重要的错误修…...

2.4 卷积1
2.4 卷积1 2.4 卷积 在了解了系统及其脉冲响应之后,人们可能会想知道是否有一种方法可以通过任何给定的输入信号(不仅仅是单位脉冲)确定系统的输出信号。卷积就是这个问题的答案,前提是系统是线性且时不变的(LTI&…...

OA项目值用户登入首页展示
1.什么是OA 办公自动化(Office Automation,简称OA)是将现代化办公和计算机技术结合起来的一种新型的办公方式。办公自动化没有统一的定义,凡是在传统的办公室中采用各种新技术、新机器、新设备从事办公业务,都属于办公自动化的领域。通过实现办公自动化,或者说实现数字化…...

如何关闭前端Chrome的debugger反调试
1、禁用浏览器断点 2. 把控制台独立一个窗口...

硬件工程师笔试面试——晶振
目录 13、晶振 13.1 基础 晶振原理图 晶振实物图 13.1.1 概念 13.1.2 工作原理 13.1.3 应用领域 13.1.4 产品类型 13.2 相关问题 13.2.1 晶振的工作原理是什么,它如何保证频率的稳定性? 13.2.2 在工业控制领域,晶振是如何确保精确度的? 13.2.3 晶振的Q值是如何…...

如何用安卓玩Java版Minecraft,安卓手机安装我的世界Java版游戏的教程
安卓手机使用FCL启动器安装我的世界Java版游戏的教程。如何用安卓玩Java版Minecraft 视频教程:https://www.bilibili.com/video/BV1CctYebEzR/ 前言 目前,安卓设备上可以用来运行Java版Minecraft的启动器主要有以下几款: PojavLauncher&a…...

linux上用yolov8训练自己的数据集(pycharm远程连接服务器)
pycharm如何远程连接服务器,看之前的文章 首先去GitHub上下载项目地址,然后下载预训练模型放到项目主目录下 然后下载数据集,我这有个推荐的数据集下载网站,可以直接下载yolov8格式的数据集(还支持其他格式的数据集&a…...

Git rebase 的使用(结合图与案例)
目录 Git rebase 的使用Git rebase 概念Git rebase 原理rebase和merge的选择 Git rebase 的使用 在 Git 中整合来自不同分支的修改主要有两种方法:merge 以及 rebase Git rebase 概念 **rebase概念:**用来重新应用提交(commits)…...

一文讲懂Mac中的环境变量
你是否曾经因为环境变量配置不当而浪费了宝贵的开发时间?你是否好奇为什么有时候在终端输入命令会提示"command not found",而有时候又能正常运行?如果你是一名Mac用户,并且希望真正掌握环境变量的奥秘,那么这篇文章将为你揭开Mac中环境变量的神秘面纱,帮助你成为一…...

将硬盘的GPT 转化为MBR格式
遇到的问题 在重新安装系统时,磁盘遇到无法空间分配给系统。 解决方式 使用Windows10镜像 U盘安装,选择磁盘时,转换磁盘格式为MBR。然后退出安装程序。 Shift F10# 输入 diskpart# 查看磁盘信息 list disk# 选择需要转换的磁盘࿰…...
C++基于select和epoll的TCP服务器
select版本 服务器 #include <arpa/inet.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <string> #include <pthread.h> #include <sys/select…...
SpringBoot 读取配置文件的4种方式
文章目录 1. Value 注解读取单个属性2. 使用 ConfigurationProperties 注解3. 通过 Environment 对象读取属性4. 使用 PropertySource 注解加载额外的配置文件 在 Spring Boot 中,application.yml 文件用于配置应用程序的属性,Spring Boot 默认会从 src/…...

【车载开发系列】ParaSoft单元测试环境配置(三)
【车载开发系列】ParaSoft单元测试环境配置(三) 【车载开发系列】ParaSoft单元测试环境配置(三) 【车载开发系列】ParaSoft单元测试环境配置(三)一. 去插桩设置Step1:静态解析代码Step2:编辑Parasoft文件Step3:确认去插桩二. 新增测试用例Step1:生成测试用例Step2:执…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...

GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...