组件测试--React Testing Library的学习 - 实践

news/2026/1/19 14:49:37/文章来源:https://www.cnblogs.com/tlnshuju/p/19501619

组件测试--React Testing Library的学习 - 实践

2026-01-19 14:38  tlnshuju  阅读(0)  评论(0)    收藏  举报

三、组件测试

在现代前端开发中,单元测试是保证代码质量和稳定性的重要手段。本文将以Button组件为例,详细介绍如何使用Jest和React Testing Library进行React组件的单元测试实践。

3.1 测试的好处

3.2 测试工具

测试的工具是使用的 React Testing Library,他是基于react-dom和react-dom/test-utils的轻量级封装,而且已经集成在了create-react-app 3.3.0+默认模板

如果需要安装可以执行

 npm install --save-dev @testing-library/react

可以通过npm test命令运行测试。

{ "scripts": {   "test": "react-scripts test"}
}

package.json中配置了测试脚本:

3.3 测试策略规定

在开始编写测试用例之前,我们需要制定明确的测试策略,确定需要测试的功能和场景。对于Button组件,我们确定了以下测试范围:

  1. 基本渲染:确保组件能够正确渲染为按钮元素
  2. 样式变化:验证不同类型、尺寸的按钮应用了正确的CSS类
  3. 状态管理:测试禁用、加载等状态的表现
  4. 交互行为:验证点击事件的触发和阻止
  5. 无障碍支持:确保组件符合无障碍标准
  6. 特殊场景:如纯图标按钮、加载状态与图标的交互

3.4 测试用例实现

1. 基础设置

首先,我们需要导入必要的测试工具和被测试组件:

import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import "@testing-library/jest-dom";
import Button, { ButtonProps, ButtonType, ButtonSize } from "./index";

为了测试图标功能,我们创建了一个模拟的Ant Design风格图标组件:

const MockIcon = () => ;

2. 基本渲染测试

test("should render a button element with default props", () => { const wrapper = render(); const button = wrapper.getByText("Click Me"); expect(button).toBeInTheDocument(); expect(button.tagName).toBe("BUTTON"); expect(button).toHaveClass("btn btn-primary btn-normal");
});

这个测试验证了:

  • 组件能够正确渲染
  • 渲染结果是一个button元素
  • 默认应用了正确的CSS类

3. 参数化测试:按钮类型和尺寸

使用Jest的test.each方法,我们可以高效地测试多种按钮类型和尺寸:

// 测试不同按钮类型
test.each([ ButtonType.Primary, ButtonType.Secondary, ButtonType.Danger, ButtonType.Warning, ButtonType.Info, ButtonType.Success, ButtonType.Outline, ButtonType.Ghost, ButtonType.Text
])('should render %s button correctly', (type) => { const wrapper = render(); const button = wrapper.getByText(type); expect(button).toHaveClass(`btn-${type}`);
});
// 测试不同按钮尺寸
test.each([[ButtonSize.Large, 'btn-large'],[ButtonSize.Normal, 'btn-normal'],[ButtonSize.Small, 'btn-small']
])('should render %s button correctly', (size, expectedClass) => { const wrapper = render(); const button = wrapper.getByText('Size Test'); expect(button).toHaveClass(expectedClass);
});

4. 状态测试:禁用和加载

// 测试禁用状态
test('should render a disabled button when disabled prop is true', () => { const wrapper = render(); const button = wrapper.getByText('Disabled'); expect(button).toBeDisabled(); expect(button).toHaveClass('btn-disabled'); expect(button).toHaveAttribute('aria-disabled', 'true');
});
// 测试加载状态
test('should render loading state correctly', () => { const wrapper = render(); const button = wrapper.getByText('Loading'); expect(button).toBeDisabled(); expect(button).toHaveClass('btn-loading btn-disabled'); expect(button).toHaveAttribute('aria-busy', 'true'); expect(button).toHaveAttribute('aria-disabled', 'true'); expect(button).toContainHTML('');
});

5. 图标按钮测试

// 测试图标按钮
test('should render button with icon', () => { const wrapper = render(); const button = wrapper.getByText('With Icon'); const icon = wrapper.getByTestId('mock-icon'); expect(button).toContainElement(icon); expect(icon.closest('.btn-icon')).toBeInTheDocument();
});
// 测试只有图标的按钮:只有图标时必须提供aria-label,这里不能通过之前的文本的方法来获取组件,使用getByRole结合name选项,它会考虑aria-label属性
test('should render icon-only button with proper accessibility attributes', () => { const wrapper = render(

6. 交互测试:点击事件

// 测试点击事件
test('should call onClick handler when button is clicked', () => { const handleClick = jest.fn();// 模拟点击事件处理函数 const wrapper = render(); const button = wrapper.getByText('Click Me'); fireEvent.click(button);// 模拟点击事件 expect(handleClick).toHaveBeenCalledTimes(1);// 验证点击事件处理函数未被调用
});
// 测试禁用状态下不触发点击事件
test('should not call onClick handler when button is disabled', () => { const handleClick = jest.fn(); const wrapper = render(); const button = wrapper.getByText('Click Me'); fireEvent.click(button); expect(handleClick).not.toHaveBeenCalled();
});

7. 其他

// 测试自定义类名test('should apply custom className to button', () => {const wrapper = render();const button = wrapper.getByText('Custom Class');expect(button).toHaveClass('custom-button');});// 测试传递额外的属性test('should pass additional props to button element', () => {const wrapper = render();const button = wrapper.getByTestId('custom-button');expect(button).toHaveAttribute('title', 'Custom Title');});// 测试无障碍属性test('should apply aria-label when provided', () => {const wrapper = render();const button = wrapper.getByText('Test');expect(button).toHaveAttribute('aria-label', 'Accessibility Test');});

3.5 测试最佳实践

通过Button组件的测试实践,我们总结了以下React组件单元测试的最佳实践:

1. 测试用户行为而非实现细节

使用React Testing Library的查询方式(如getByTextgetByRole)模拟用户的实际行为,而不是直接测试组件的内部实现。

2. 全面覆盖各种场景

测试应该覆盖组件的所有功能点,包括:

  • 基本渲染
  • 所有属性组合
  • 各种状态(正常、禁用、加载等)
  • 交互行为
  • 边缘情况

3. 使用参数化测试减少重复代码

对于类似的测试场景(如不同类型、尺寸的按钮),使用test.each可以减少重复代码,提高测试的可维护性。

4. 确保无障碍支持

测试组件的无障碍属性(如aria-labelaria-disabledaria-busy),确保组件符合无障碍标准。

5. 测试组件的集成性

除了测试组件的独立功能外,还应该测试组件与其他元素的集成(如图标、加载指示器等)。

3.6 常见测试问题及解决方案

1. 如何测试只有图标的按钮?

对于没有可见文本的按钮,我们需要使用aria-label提供无障碍标签,并使用getByRole('button', { name: '标签内容' })来查找元素。

// 错误的方式
const button = wrapper.getByText('Icon Button'); // 会失败,因为没有可见文本
// 正确的方式
const button = wrapper.getByRole('button', { name: 'Icon Button' }); // 会考虑aria-label

2. 如何测试组件的内部HTML结构?

使用toContainHTML可以测试组件是否包含特定的HTML结构:

expect(button).toContainHTML('');

3. 如何模拟用户交互?

使用fireEvent可以模拟用户的各种交互行为:

fireEvent.click(button); // 模拟点击事件
fireEvent.mouseEnter(button); // 模拟鼠标进入事件

参考资料

  • Jest官方文档
  • React Testing Library官方文档
  • WAI-ARIA无障碍标准

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

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

相关文章

快速理解Multisim数据库层级结构与建模逻辑

深入理解Multisim数据库:从元件调用到自定义建模的全链路解析你有没有遇到过这种情况——在Multisim里画电路,想找个特定型号的MOSFET,翻遍“Transistors”文件夹却怎么也找不到?或者好不容易导入了厂商提供的SPICE模型&#xff0…

手把手教你用DDU优化游戏本显卡性能

用对工具,榨干每一分性能:DDU如何让游戏本显卡“满血复活” 你有没有遇到过这种情况?明明是RTX 3060的游戏本,玩《艾尔登法环》却频频掉帧;刚更新完NVIDIA驱动,外接显示器突然黑屏无信号;或者系…

2026年热门的岩相切割机,岩相研磨机,岩相抛光机厂家选型推荐榜单 - 品牌鉴赏师

引言在 2026 年的工业领域,岩相切割机、岩相研磨机、岩相抛光机作为重要的材料检测设备,其性能与品质对于科研、生产等环节的精准度有着至关重要的影响。为了给广大用户提供一份客观、公正、真实的厂家选型参考,我们…

vue原创打赏漫画商城的设计与实现沙箱支付

目录摘要开发技术源码文档获取/同行可拿货,招校园代理 :文章底部获取博主联系方式!摘要 随着数字内容消费的快速增长,原创漫画平台需要一种便捷的支付解决方案来支持用户打赏和商城交易。基于Vue.js框架开发的原创打赏漫画商城,结…

2026年比较好的金相切割耗材,金相,金相振动抛光液厂家行业优质名录 - 品牌鉴赏师

引言在 2026 年的工业制造与材料研究领域,金相切割耗材、金相设备以及金相振动抛光液等产品的质量和性能对于材料分析和检测起着至关重要的作用。为了给广大企业和研究机构提供可靠的采购参考,我们依据一系列科学、严…

AI写作大师Qwen3-4B部署:本地开发环境配置

AI写作大师Qwen3-4B部署:本地开发环境配置 1. 引言 1.1 学习目标 本文将详细介绍如何在本地开发环境中部署 Qwen3-4B-Instruct 模型,构建一个功能完整的 AI 写作与代码生成系统。通过本教程,读者将掌握从环境准备到服务启动的全流程操作&a…

如何防止电信诈骗

​ 安全与方便是相互矛盾的,为了方便就会牺牲安全性,这就是为什么诈骗日渐猖獗。 1.App store不要登录 因为+86手机号实名。苹果的商店强制登陆,所以换Android最好是老年机,里面传感器少,收集个人信息少。根据你下…

软路由在企业SD-WAN中的角色:通俗解释

软路由如何重塑企业广域网?从“铁盒子”到“活网络”的实战解析你有没有经历过这样的场景:新开了一个分公司,等了三周才把路由器寄到、上架、配置上线;或者某条MPLS专线一抖动,整个财务系统的ERP就卡得打不开&#xff…

2025年直驱电动螺旋压力机厂家权威推荐榜单:电动数控螺旋压力机/螺旋电动压力机/数控电动螺旋压力机/1000吨电动螺旋压力机/电动程控螺旋压力机源头厂家精选

在全球制造业向智能化、高效化、精密化深度转型的背景下,锻造行业的核心装备——直驱电动螺旋压力机,正凭借其无可比拟的技术优势,成为产业升级的关键驱动力。根据行业报告,2025年全球直驱式电动螺旋压力机市场规模…

开源大模型轻量化趋势一文详解:DeepSeek-R1架构优势与落地实践

开源大模型轻量化趋势一文详解:DeepSeek-R1架构优势与落地实践 1. 背景与技术演进 近年来,随着大语言模型在自然语言理解、代码生成和数学推理等任务上的持续突破,其参数规模也迅速膨胀至百亿甚至千亿级别。然而,这种“越大越好…

Sambert性能优化秘籍:让语音合成速度提升3倍

Sambert性能优化秘籍:让语音合成速度提升3倍 1. 引言:工业级中文TTS的性能瓶颈与突破方向 随着智能客服、虚拟主播、有声阅读等应用场景对语音自然度和情感表达要求的不断提升,基于深度学习的端到端语音合成模型(如Sambert-HiFi…

保姆级教程:Voice Sculptor语音合成模型快速部署与使用指南

保姆级教程:Voice Sculptor语音合成模型快速部署与使用指南 1. 快速启动 1.1 启动 WebUI 在终端中执行以下命令以启动 Voice Sculptor 应用: /bin/bash /root/run.sh执行成功后,终端将输出类似如下信息: Running on local UR…

Gerber文件转成PCB文件:CAM处理完整指南

从 Gerber 到 PCB:一次深入的 CAM 处理实战之旅你有没有遇到过这样的场景?手头有一块老旧电路板,客户急需复刻,但原始设计文件早已丢失;或是收到一批代工厂发来的 Gerber 文件,想快速确认是否与你的设计一致…

2026模切机设备厂家权威推荐榜单:平压平模切机/白卡纸模切机/灰板模切机 /白卡模切机/自动模切机源头厂家精选。

在现代印刷包装与精密制造领域,模切技术扮演着至关重要的角色。据统计,2025年全球工业模切机市场规模已达数十亿美元,并以稳健的复合年增长率持续扩张。作为核心的加工设备,模切机广泛应用于消费电子、烟酒包装、日…

Qwen3-4B-Instruct部署实战:4090D单卡实现256K上下文解析

Qwen3-4B-Instruct部署实战:4090D单卡实现256K上下文解析 1. 背景与技术价值 随着大模型在自然语言处理领域的广泛应用,长上下文理解能力成为衡量模型实用性的重要指标。传统大模型通常受限于8K或32K的上下文长度,在处理长文档摘要、代码库…

网络安全威胁狩猎硬核指南:入侵检测与异常分析的核心原理与实战 ### 一,网络安全漏洞 * 安全威胁是指所有能够对计算机网络信息系统的网络服务和网络信息的机密性,可用性和完整性产生阻碍,破坏

一,网络安全漏洞 安全威胁是指所有能够对计算机网络信息系统的网络服务和网络信息的机密性,可用性和完整性产生阻碍,破坏或中断的各种因素。安全威胁可分为人为安全威胁和非人为安全威胁两大类。 1,网络安全漏洞威胁 漏洞分析的…

SpringBoot中基于JWT的单token授权和续期方案

在前后端分离架构中,用户登录成功后,后端颁发JWT token至前端,该token被安全存储于LocalStorage。随后,每次请求均自动携带此token于请求头中,以验证用户身份。后端设有过滤器,拦截并校验token有效性&#…

别被“骗”了,它竟是伪装成小国的领土大国

在欧洲版图上,丹麦常以“袖珍强国”的形象示人——本土面积仅4.3万平方公里,人口不足600万,是北欧兼具童话气息与高福利的小国。 但鲜有人知,这片位于斯堪的纳维亚半岛南端的土地,凭借对格陵兰岛的主权掌控&#xff0…

WinDbg使用教程:从零实现内存泄漏追踪的操作指南

用 WinDbg 玩透内存泄漏追踪:从零开始的实战指南 你有没有遇到过这样的情况?某个服务跑着跑着内存蹭蹭上涨,几天后直接 OOM 崩溃。重启能缓解,但治标不治本。日志里查不到线索,代码翻来覆去也没发现明显漏 delete 的…

你可能从来没有,从这个视角看我国沿海省份

我们换个角度看沿海各省份之后,有网友说像一只海马,也有网友说像北斗,还有网友说像一把锋利的镰刀。你觉得,它到底像什么呢?换个视角之后,你看到了什么?