Jest进阶知识:深入测试 React Hooks-确保自定义逻辑的可靠性

测试 React Hooks

在 React 开发中,Hooks 是一个非常重要的功能模块,允许开发者在函数组件中使用状态和其他 React 特性。自定义 Hooks 作为一种公共逻辑的抽离,经常被多个组件复用,因此对其测试是非常必要的。

然而,由于 Hooks 必须在组件内部使用,直接测试它们并不像普通函数那样简单。幸运的是,@testing-library/react-hooks 提供了一种简便的方法来测试 React Hooks。

安装和使用 @testing-library/react-hooks

首先,确保你已经安装了 @testing-library/react-hooks

npm install @testing-library/react-hooks
快速上手示例

假设我们有一个自定义 Hook useCounter,用于创建一个计数器:

// 自定义 hook
// 这是一个计数器的自定义 hook
// 内部维护了一个计数的值,以及修改这个值的一些方法import { useState } from "react";interface Options {min?: number;max?: number;
}type ValueParam = number | ((c: number) => number);// 该方法主要是做一个边界的判断,如果超过了边界,那么就取边界值
function getTargetValue(val: number, options: Options = {}) {const { min, max } = options;let target = val;// 判断有没有超过最大值,如果超过了,那么我们就取最大值if (typeof max === "number") {target = Math.min(max, target);}// 判断有没有超过最小值,如果超过了,那么我们就取最小值if (typeof min === "number") {target = Math.max(min, target);}return target;
}// useCounter(100, {min : 1, max : 1000})
function useCounter(initialValue = 0, options: Options = {}) {const { min, max } = options;// 设置初始值,初始值就为 initialVaule// 初始值是该自定义 hook 内部维护的状态,用来表示计数器的数值const [current, setCurrent] = useState(() => {return getTargetValue(initialValue, {min,max,});});// 设置新的值// 在设置新的值的时候,调用了 getTargetValue 来判断新值是否越界const setValue = (value: ValueParam) => {setCurrent((c) => {const target = typeof value === "number" ? value : value(c);return getTargetValue(target, {max,min,});});};// 下面就是自定义 hook 提供的 4 个方法// 用于修改计数器的数值// 增加const inc = (delta = 1) => {setValue((c) => c + delta);};// 减少const dec = (delta = 1) => {setValue((c) => c - delta);};// 设置const set = (value: ValueParam) => {setValue(value);};// 重置const reset = () => {setValue(initialValue);};// 像外部暴露return [current,{inc,dec,set,reset,},] as const;
}export default useCounter;

接下来,我们将对这个自定义 Hook 进行测试。

测试同步操作
import useCounter from "../hooks/useCounter";
import { renderHook, act } from "@testing-library/react";test("可以做加法", () => {// Arrange(准备)// result ---> {current : [0, {inc, dec, set, reset}]}const { result } = renderHook(() => useCounter(0));// Act(行为)act(() => result.current[1].inc(2));// Assert(断言)expect(result.current[0]).toEqual(2);
});test("可以做减法", () => {// Arrange(准备)// result ---> {current : [0, {inc, dec, set, reset}]}const { result } = renderHook(() => useCounter(0));// Act(行为)act(() => result.current[1].dec(2));// Assert(断言)expect(result.current[0]).toEqual(-2);
});test("可以设置值", () => {// Arrange(准备)// result ---> {current : [0, {inc, dec, set, reset}]}const { result } = renderHook(() => useCounter(0));// Act(行为)act(() => result.current[1].set(100));// Assert(断言)expect(result.current[0]).toEqual(100);
});test("可以重置值", () => {// Arrange(准备)// result ---> {current : [0, {inc, dec, set, reset}]}const { result } = renderHook(() => useCounter(0));// Act(行为)act(() => result.current[1].set(100));act(() => result.current[1].reset());// Assert(断言)expect(result.current[0]).toEqual(0);
});test("可以设置最大值", () => {// Arrange(准备)// result ---> {current : [0, {inc, dec, set, reset}]}const { result } = renderHook(() => useCounter(0, { max: 100 }));// Act(行为)act(() => result.current[1].set(1000));// Assert(断言)expect(result.current[0]).toEqual(100);
});test("可以设置最小值", () => {// Arrange(准备)// result ---> {current : [0, {inc, dec, set, reset}]}const { result } = renderHook(() => useCounter(0, { min: -100 }));// Act(行为)act(() => result.current[1].set(-1000));// Assert(断言)expect(result.current[0]).toEqual(-100);
});
使用自定义 Hook

测试通过后,可以在组件中安全地使用这个自定义 Hook:

import "./App.css";
import useCounter from "./hooks/useCounter";function App() {const [current, { inc, dec, set, reset }] = useCounter(5, { min: 0, max: 10 });return (<div className="App"><div>{current}</div><button onClick={() => dec(1)}>-</button><button onClick={() => inc(1)}>+</button><button onClick={() => set(100)}>set</button><button onClick={() => reset()}>reset</button></div>);
}export default App;
测试异步操作

假设我们在 useCounter 中添加了一个异步的增加方法:

const asyncInc = (delta = 1) => {setTimeout(() => {setValue((c) => c + delta);}, 2000);
};

测试异步操作时,可以使用 jestuseFakeTimersadvanceTimersByTime 方法来模拟时间流逝:

test("测试异步的增加", async () => {jest.useFakeTimers();const { result } = renderHook(() => useCounter(0));act(() => result.current[1].asyncInc(2));expect(result.current[0]).toEqual(0); // 初始值未变await act(() => jest.advanceTimersByTime(2000)); // 模拟时间流逝expect(result.current[0]).toEqual(2); // 值已更新jest.useRealTimers();
});

结论

通过本文的介绍,我们了解了如何使用 @testing-library/react-hooks 测试 React Hooks,特别是自定义 Hooks。通过对 Hooks 的行为进行测试,可以确保它们在不同情况下的表现符合预期,从而提高代码的可靠性和可维护性。

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

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

相关文章

优选算法第五讲:位运算模块

优选算法第五讲&#xff1a;位运算模块 1.常见的位运算总结2.判断字符是否唯一3.丢失的数字4.两整数之和5.只出现一次的数字II6.消失的两个数字 1.常见的位运算总结 2.判断字符是否唯一 链接: link class Solution { public:bool isUnique(string astr) {if(astr.size() >…

计算机视觉算法真的难学吗?这些技巧让你轻松掌握

在当今这个数字化迅猛发展的时代&#xff0c;计算机视觉作为人工智能的重要分支&#xff0c;正在逐渐改变我们的生活和工作方式。很多人可能会觉得计算机视觉算法难以掌握&#xff0c;尤其是在面对复杂的数学和编程时&#xff0c;常常会感到无从下手。不过&#xff0c;实际上&a…

基于YOLO11/v10/v8/v5深度学习的老鼠智能检测系统设计与实现【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

机器学习—前向传播的一般实现

可以写一个函数来实现一个密集的层&#xff0c;那是神经网络的单层&#xff0c;所以定义稠密函数&#xff0c;它将上一层的激活作为输入以及给定层神经元的参数w和b。看下边图片所展示的例子&#xff0c;把所有这些权重向量堆叠成一个矩阵&#xff0c;wnp.array([[1,-3,5][2,4,…

高清烟花视频素材下载网站推荐

无论是庆祝节日、婚礼&#xff0c;还是各种欢庆活动&#xff0c;烟花总能瞬间点燃气氛&#xff0c;带来视觉上的震撼。在视频作品中加入绚丽的烟花瞬间&#xff0c;能够立刻提升画面的冲击力和节庆氛围。那么&#xff0c;高清烟花视频素材去哪下载呢&#xff1f;今天&#xff0…

Java异常体系结构

在Java编程中&#xff0c;异常处理是一个重要的概念。理解Java的异常体系结构以及如何捕获和处理异常&#xff0c;对于编写健壮的程序至关重要。本文将详细介绍Java异常体系结构的组成部分&#xff0c;以及异常的捕获和处理机制。 一、Java异常体系结构 Java的异常体系结构可以…

免费,基于React + ECharts 国产开源 IoT 物联网 Web 可视化数据大屏

文末查看开源项目地址 Light Chaser 是一款国产开源免费的基于 React18、Vite5、TypeScript5 技术栈实现的 Web 可视化大屏设计工具&#xff0c;支持Docker方式部署&#xff0c;支持MySQL、PostgreSQL、SQL Server、Oracle 数据源。 你可以简单快速地搭建数据可视化展示、数据报…

【解决】Pico 串流 Unity 开发环境 Preview 黑屏问题

开发平台&#xff1a;Unity 6.0 开发工具&#xff1a;Pico SDK   一、问题描述 在 Unity 开发环境下运行 测试 PicoVR 表现时&#xff0c;出现 Game视窗 PicoVR投屏 呈现黑屏效果。详细背景如下&#xff1a; UnitySwitch PlateformPICO Integration SDKPICO Live Preview6…

pytest高版本兼容test_data[“log“] = _handle_ansi(“\n“.join(logs))错误

一、问题现象&#xff1a; 执行seleniumpytest结束时报: INTERNALERROR> File "D:\workspace\pytestframe\.venv\Lib\site-packages\pytest_html\report_data.py", line 141, in add_test INTERNALERROR> test_data["log"] _handle_ansi(&q…

编译工具与文件学习(一)-YAML、repos、vcstoolcolcon

YAML YAML&#xff08;YAML Ain’t Markup Language&#xff09;是一种人类可读的数据序列化格式&#xff0c;常用于配置文件、数据交换和存储结构化数据。YAML 的设计目标是简洁、易读&#xff0c;并且能够表示复杂的数据结构。 YAML 文件的基本语法 基本结构&#xff1a; Y…

信息学科平台系统构建:Spring Boot框架深度解析

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

从传统服务器到虚拟化:虚拟机 VM 如何改变计算游戏规则?

目录 VMware 数据中心虚拟化入门Ⅰ—— 虚拟机 Virtual Machine&#xff08;VM&#xff09;1. 虚拟机 Virtual Machine, VM阅读本文后可以获得以下信息1.1 什么是虚拟机问题思考&#xff08;1&#xff09;从传统服务器到虚拟化服务器&#xff08;2&#xff09;问题&#xff1a;…

双向链表及如何使用GLib的GList实现双向链表

双向链表是一种比单向链表更为灵活的数据结构&#xff0c;与单向链表相比可以有更多的应用场景&#xff0c;本文讨论双向链表的基本概念及实现方法&#xff0c;并着重介绍使用GLib的GList实现单向链表的方法及步骤&#xff0c;本文给出了多个实际范例源代码&#xff0c;旨在帮助…

MySQL 数据库之库操作

文章目录 1. 什么是数据库2. 基础概念2.1 连接数据库2.2 服务器&#xff0c;数据库&#xff0c;表关系2.3 SQL分类 3. 库的操作3.1 创建&#xff0c;选择&#xff0c;查看数据库3.2 字符集和默认校验规则 3.3 操纵数据库3.3.1 数据库查看3.3.2 数据库删除3.3.3 数据库修改 4. 其…

Windows安装多个NodeJS版本

下载nvm管理工具&#xff0c;下载完成解压安装 https://github.com/coreybutler/nvm-windows/releases 选择nvm安装位置 选择nvm安装node版本的安装位置 如果提示你已经安装的有nodejs&#xff0c;提示你是否通过nvm管理nodejs&#xff0c;选择是&#xff0c;继续安装即可…

使用NVM自由切换nodejs版本

一、NVM介绍 在日常开发中&#xff0c;我们可能需要同时进行多个不同NodeJS版本的项目开发&#xff0c;每个项目所依赖的nodejs版本可能不一致&#xff0c;我们如果只安装一个版本的nodejs&#xff0c;就可能出现node版本冲突问题&#xff0c;导致项目无法启动。这种情况下&am…

parseInt 是一个内置的 JavaScript 函数,用于将字符串转换为整数。

parseInt(options.checkNumber, 10) 中的 10 表示将字符串转换为十进制整数。 解释 parseInt 函数&#xff1a; parseInt 是一个内置的 JavaScript 函数&#xff0c;用于将字符串转换为整数。它有两个参数&#xff1a; 第一个参数是要转换的字符串。第二个参数是转换时使用的基…

Qt中的Model与View 4:QStandardItemModel与QTableView

目录 QStandardItemModel API QTableView 导航 视觉外观 坐标系统 API 样例&#xff1a;解析一个表格txt文件 QStandardItemModel QStandardItemModel 可用作标准 Qt 数据类型的存储库。它是模型/视图类之一&#xff0c;是 Qt 模型/视图框架的一部分。它提供了一种基于…

[Unity Demo]从零开始制作空洞骑士Hollow Knight第十九集:制作过场Cutscene系统

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、制作过场Cutscene系统 1.制作基本的视频过场和动画过场2.制作决定过场系统的播放顺序Sequence以及切换场景以后的逻辑处理二、制作跳过过场Cutscene的MenuS…

【设计模式系列】桥接模式(十三)

一、什么是桥接模式 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;其核心目的是将抽象部分与实现部分分离&#xff0c;使它们可以独立地变化。这种模式主要用于处理那些在设计时无法确定实现细节的场合&#xff0c;或者需要在多个实现之间…