[React Jest] 测试 Hook

news/2025/3/10 21:37:18/文章来源:https://www.cnblogs.com/Answer1215/p/18694740

在进行 React 开发的时候,还有一个非常重要的功能模块,那就是 Hook,自定义 Hook 作为一块公共逻辑的抽离,也会像组件一样被用到多个地方,因此对 Hook 的测试也是非常有必要的。

Hook 没有办法像普通函数一样直接进行测试,因为在 React 中规中,Hook 必须要在组件里面使用,否则会报错。

16835247590337

有一种方案,就是为了测试自定义 Hook,专门写一个组件,然后通过上一小节我们所讲的测试组件的方式来测试这些 Hook,这种方案是可以的,但是比较麻烦。

在 Testing library 里面就提供了一个 @testing-library/react-hooks 的扩展库,专门用于测试 react hooks。

该扩展库对应的官网地址:https://react-hooks-testing-library.com/

快速上手示例

首先我们有如下的自定义 Hook:

// 自定义 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);
});

首先我们使用到了 renderHook,这个方法的背后,会去渲染一个测试组件,在组件中可以使用自定义 hook,从 renderHook 的返回值中可以解构出自定义 Hook 中返回的状态值以及修改状态值的方法。

接下来使用 act 方法,该方法主要是用来模拟 react 组件的交互行为,并且触发更新。

最后进行 expect 断言。

注意,上面的 renderHook 以及 act 方法是从 @testing-library/react 解构出来的,但是以前在旧版本中是需要安装 @testing-library/react-hooks 扩展库,然后从这个扩展库中解构 renderHook 和 act 方法,目前新版本已经将这两个方法整合到 @testing-library/react 这个扩展库里面了。

经过测试之后,就可以证明我们这个自定义 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;

测试异步的 Hook

有些时候我们的 Hook 会包含一些异步的代码,例如我们对上面的计数器进行一个修改,增加异步的方法,如下:

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

之后在进行测试的时候,就可以使用前面我们所学过的 fakeTime 来模拟时间流逝,代码如下:

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();
});

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

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

相关文章

07_LaTeX之绘图功能

除了排版文字,$\LaTeX{}$ 也支持用代码表示图形。不同的扩展已极大丰富了 $\LaTeX{}$ 的图形功能,`TikZ` 就是其中之一。本章将带你了解一些基本的绘图功能。07_\(\LaTeX{}\) 之绘图功能 目录07_\(\LaTeX{}\) 之绘图功能绘图语言简介\(\textrm{TikZ}\) 绘图语言\(\textrm{Tik…

《计算机网络》笔记——第四章 网络层

目录第4章 网络层网络层提供的两种服务网际协议IP虚拟互连网络分类的IP地址IP地址与硬件地址地址解析协议ARPIP数据报的格式IP层转发分组的流程划分子网和构造超网划分子网无分类编址CIDR(构造超网)最长前缀匹配网际控制报文协议ICMPICMP的应用互联网的路由选择协议 第4章 网络…

《计算机网络》笔记——第三章 数据链路层

计算机网络(第7版)谢希仁目录第3章 数据链路层使用点对点信道的数据链路层三个基本问题(1) 封装成帧(2) 透明传输(3) 差错检测点对点协议PPPPPP协议特点PPP协议的组成PPP协议的帧格式PPP协议的工作状态使用广播信道的数据链路层CSMA/CD协议使用集线器的星形拓扑以太网的信道利…

《计算机网络》笔记——第一章 概述

计算机网络(第7版)谢希仁目录第一章 概述互联网基础结构计算机网络的分类互联网的组成计算机网络的性能计算机网络体系结构TCP/IP的体系结构 第一章 概述 互联网基础结构 互联网服务提供者ISP(Internet Service Provider) 互联网交换点IXP(Internet Exchange Point)计算机…

解析几何笔记

数学 目录数学一、双根式Ex 1Ex 2二、极坐标Ex 1Ex 2三、平移齐次化Ex 1四、同构式Ex 1五、定比点差法Ex 1Ex 2六、极点极线和调和点列 一、双根式 将圆锥曲线和直线联立,展开并做韦达定理是困难的。但是考虑到任意二次方程都可以写成 \(g(x) = a(x_1 - x)(x_2 - x) = 0\) 的形…

线段树总集

引入 一个数列,单点修改(加),区间查询(和)。 上述问题有很多种解法,如树状数组、分块、平衡树等,今天的主题是著名的线段树。 正题 (不确保按难度升序排序,自己看着目录调顺序吧) 线段树基本原理 因为需要区间查询,所以我们希望有一些捷径能将部分的数的和提前算好…

攻防世界reverse难度3

真难做啊攻防世界Reverse3 哎,坐牢,哎,坐牢. 我从来没有觉得ctf有趣过.jpg painful secret-string-400 js虚拟机混淆 我理解错了,一直以为是所有代码翻译一遍. 结果发现是读取字节然后执行代码. 也就是说,它可以直接翻译成ascii码去掉无用的字节码.(还是看wp知道的,看的时候都懵…

线段树总集 1

引入 一个数列,单点修改(加),区间查询(和)。 上述问题有很多种解法,如树状数组、分块、平衡树等,今天的主题是著名的线段树。 正题 (不确保按难度升序排序,自己看着目录调顺序吧) 线段树基本原理 因为需要区间查询,所以我们希望有一些捷径能将部分的数的和提前算好…

央视蛇年春晚Counting Stars中文翻译!

视频链接 : httpe990-5b4b-4262-95d7-7ea2f9425874&modal_id=7464989004501486900&type=general 《Counting Stars》是美国流行摇滚乐队OneRepublic演唱的一首歌曲,由主唱瑞恩泰德创作。这首歌收录于乐队的第三张录音室专辑《Native》中,以其充满活力的旋律和深刻的…

htb Networked walkthrough

nmap扫描只有 22 80 443 端口 443端口访问不了 所以入手点只有80端口了 direarch 扫描网站发现了几个有意思的路径backup 路径下发现了一个压缩tar包下载下来解压看看内容发现是网站源码需要代码审计我审计了半天也没发现什么问题看看wp说是加个gif89a的文件头就可以上传文件 我…

Janus Pro:DeepSeek 开源革新,多模态 AI 的未来

Janus Pro 是 DeepSeek 开发的一个开源多模态人工智能框架,它通过集成视觉和语言处理能力,提供了高性能的多模态任务处理能力。 在线体验: https://deepseek-januspro.com/ 背景 Janus Pro 于2025年1月发布,是一个开源的多模态AI框架,能够同时处理视觉和语言信息。它采用了…

2025-01-29 闲话

2025-01-29 闲话我尽量不在大年初一整尬的。于是选择了集句?? 最近单曲循环了两首粤语歌。红日 AH.. AH... AH 命运就算颠沛流离 命运就算曲折离奇 命运就算恐吓着你 做人没趣味 别流泪 心酸 更不应舍弃 我愿能一生永远陪伴你 命运就算颠沛流离 命运就算曲折离奇 命运就算恐吓…