react+jest+enzyme配置及编写前端单元测试UT

原文合集地址如下,有需要的朋友可以关注

本文地址

合集地址

文章目录

  • 安装及配置
  • enzyme渲染
  • 测试技巧
    • 一、常见测试
    • 二、触发ant design组件
    • 三、使用redux组件
    • 四、使用路由的组件
    • 五、mock接口网络请求
    • 六、mock不需要的子组件

安装及配置

  1. 安装相关库:
    首先,使用npm或yarn安装所需的库。
npm install --save-dev jest enzyme enzyme-adapter-react-16 enzyme-to-json
  1. 配置Jest:
    在项目根目录下创建一个jest.config.js文件,并配置Jest。
// jest.config.js
module.exports = {setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],testEnvironment: 'jsdom',moduleNameMapper: {'\\.(css|less)$': 'identity-obj-proxy',},
};

在上述配置中,设置了setupFilesAfterEnvsrc/setupTests.js,指定了测试环境为jsdom,并设置了模块名称映射以处理CSS和LESS文件。

  1. 创建setupTests.js文件:
    在项目的src目录下创建一个setupTests.js文件,并进行Enzyme的初始化和配置。
// src/setupTests.js
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';Enzyme.configure({ adapter: new Adapter() });

在上述代码中,导入Enzyme和Enzyme适配器,并使用适配器初始化Enzyme。

  1. 编写测试用例:
    在测试目录中创建一个与要测试的组件对应的测试文件,并编写测试用例。
import React from 'react';
import { mount } from 'enzyme';
import YourComponent from '../YourComponent';describe('YourComponent', () => {it('renders correctly', () => {const component = mount(<YourComponent />);expect(component.find('.your-class').text()).toBe('Hello World');});
});

在上述代码中,使用mount方法来渲染组件,并使用Enzyme提供的API来查找组件中的元素,并进行断言验证。

  1. 运行测试:
    在终端中运行测试命令,以执行测试用例。
npm run test

Jest将自动查找并执行项目中以.test.js.spec.js结尾的文件中的测试用例。

enzyme渲染

Enzyme提供了三种常用的渲染方式,分别是shallowmountrender。这些渲染方式在测试组件时具有不同的特点和用途。

  1. shallow 渲染:
    shallow 渲染是Enzyme的浅层渲染方式,它仅渲染被测试组件本身,而不渲染其子组件。
import { shallow } from 'enzyme';
import YourComponent from '../YourComponent';test('测试组件渲染', () => {const wrapper = shallow(<YourComponent />);// 对被测试组件进行断言和验证
});

使用shallow渲染时,被测试组件的子组件将被替换为占位符,并且无法直接访问子组件。这使得测试更加轻量且快速,适用于对被测试组件本身的行为进行测试。

  1. mount 渲染:
    mount 渲染是Enzyme的全渲染方式,它会将被测试组件及其子组件完全渲染到真实的DOM中。这使得可以模拟实际的组件嵌套和交互,并对其进行全面的测试。
import { mount } from 'enzyme';
import YourComponent from '../YourComponent';test('测试组件渲染', () => {const wrapper = mount(<YourComponent />);// 对被测试组件及其子组件进行断言和验证
});

使用mount渲染时,被测试组件及其子组件将在真实的DOM中进行渲染和交互。这使得可以测试组件的交互、生命周期方法和子组件的行为。

  1. render 渲染:
    render 渲染是Enzyme的静态渲染方式,它将组件渲染为静态的HTML字符串,不涉及真实的DOM操作。这使得可以对组件的输出进行快照测试,以验证其渲染结果是否符合预期。
import { render } from 'enzyme';
import YourComponent from '../YourComponent';test('测试组件渲染', () => {const wrapper = render(<YourComponent />);// 对组件输出的HTML进行断言和验证
});

使用render渲染时,被测试组件及其子组件将以静态HTML字符串的形式输出,可以方便地进行快照测试。
下面的例子中使用到的渲染方式只是举例,结合实际情况使用mount、shalldow或者render都是可以的。

测试技巧

一、常见测试

  1. 示例:测试组件渲染和属性传递
    假设有一个简单的React组件 Button,接收一个label属性,并在按钮上显示该标签。可以编写一个测试用例来验证组件是否正确渲染和传递属性。
import React from 'react';
import { shallow } from 'enzyme';
import Button from '../Button';describe('Button', () => {it('renders correctly with label prop', () => {const label = 'Click me';const wrapper = shallow(<Button label={label} />);expect(wrapper.text()).toBe(label);});
});

在上述例子中,使用shallow渲染方法来渲染Button组件,并使用expecttoBe断言验证按钮上的文本是否与传递的标签相匹配。

  1. 示例:模拟事件处理
    假设有一个表单组件 LoginForm,其中包含一个提交按钮。可以编写一个测试用例来模拟按钮点击事件,并验证相应的事件处理函数是否被调用。
import React from 'react';
import { mount } from 'enzyme';
import LoginForm from '../LoginForm';describe('LoginForm', () => {it('calls onSubmit handler on button click', () => {const onSubmit = jest.fn();const wrapper = mount(<LoginForm onSubmit={onSubmit} />);wrapper.find('button').simulate('click');expect(onSubmit).toHaveBeenCalledTimes(1);});
});

在上述例子中,使用mount渲染方法来渲染LoginForm组件,并使用simulate方法模拟按钮的点击事件。然后,使用expecttoHaveBeenCalledTimes断言验证onSubmit函数是否被调用了一次。

  1. 示例:异步操作的处理
    如果组件中包含异步操作,可以使用async/awaitdone回调函数来处理异步测试。
import React from 'react';
import { mount } from 'enzyme';
import AsyncComponent from '../AsyncComponent';describe('AsyncComponent', () => {it('renders data correctly after fetching', async () => {const fetchData = () => {return new Promise((resolve) => {setTimeout(() => {resolve('Data');}, 1000);});};const wrapper = mount(<AsyncComponent fetchData={fetchData} />);expect(wrapper.text()).toBe('Loading...');await Promise.resolve(); // 等待异步操作完成wrapper.update();expect(wrapper.text()).toBe('Data');});
});

在上述例子中,使用await关键字等待异步操作的完成,并使用wrapper.update()手动更新组件,以便正确渲染异步操作后的数据。

二、触发ant design组件

使用Ant Design的组件时,可以通过模拟事件或直接调用组件的方法来触发各种操作。下面是一些常见组件的触发方法示例:

  1. Input 输入框:
import { mount } from 'enzyme';
import { Input } from 'antd';test('触发Input输入', () => {const wrapper = mount(<Input />);// 模拟输入wrapper.find('input').simulate('change', { target: { value: 'Hello' } });// 模拟回车wrapper.find('input').simulate('keydown', { keyCode: 13, which: 13 }
});
// 模拟失去焦点
test('模拟输入框失去焦点', () => {const onBlur = jest.fn(); // 失去焦点时调用的函数const wrapper = mount(<YourComponent onBlur={onBlur} />);// 找到输入框元素,并触发失去焦点事件wrapper.find('input').simulate('blur');wrapper(onBlur).toHaveBeenCalled();
});

在上述例子中,使用simulate方法模拟输入框的change事件,并传递了一个模拟的event对象,其中target.value表示输入的值。

  1. Select 选择器:
import { mount } from 'enzyme';
import { Select } from 'antd';test('直接调用Select方法更新选项', () => {const wrapper = mount(<Select><Select.Option value="option1">Option 1</Select.Option><Select.Option value="option2">Option 2</Select.Option></Select>);const selectInstance = wrapper.find('Select').instance();// 更新选项selectInstance.updateOptions([{ value: 'option3', label: 'Option 3' },{ value: 'option4', label: 'Option 4' },]);
});

在上述例子中,使用 simulate 方法模拟点击下拉菜单按钮的 mousedown 事件,然后模拟点击第一个选项的 click 事件来选择该选项。

  1. Checkbox 复选框:
import { mount } from 'enzyme';
import { Checkbox } from 'antd';test('触发Checkbox选择', () => {const wrapper = mount(<Checkbox>Checkbox</Checkbox>);wrapper.find('input').simulate('change', { target: { checked: true } });
});

在上述例子中,使用simulate方法模拟复选框的change事件,并传递了一个模拟的event对象,其中target.checked表示复选框的选中状态。

  1. Dropdown 下拉菜单:
import { mount } from 'enzyme';
import { Dropdown, Menu } from 'antd';test('触发Dropdown菜单', () => {const menu = (<Menu><Menu.Item key="1">Option 1</Menu.Item><Menu.Item key="2">Option 2</Menu.Item></Menu>);const wrapper = mount(<Dropdown overlay={menu}><a href="#">Dropdown</a></Dropdown>);wrapper.find('a').simulate('click');
});

在上述例子中,使用simulate方法模拟下拉菜单的触发事件,例如click事件。

  1. 模拟文件上传
    在React中,由于安全性的限制,不能直接模拟文件上传的完整流程。但是,可以通过模拟触发change事件来模拟用户选择文件的行为。这样可以触发相应的文件上传逻辑。

以下是一个示例代码,演示了如何使用simulate方法来模拟文件上传:

import { mount } from 'enzyme';test('模拟文件上传', () => {const onFileUpload = jest.fn(); // 模拟文件上传时调用的函数const wrapper= mount(<YourComponent onFileUpload={onFileUpload} />);// 创建一个模拟的File对象const file = new File(['文件内容'], 'filename.txt', { type: 'text/plain' });// 创建一个模拟的事件对象,设置target.files为模拟的File对象const event = {target: { files: [file] },};// 找到文件上传的input元素,并触发change事件wrapper.find('input[type="file"]').simulate('change', event);expect(onFileUpload).toHaveBeenCalledWith(file);
});

在上述代码中,创建了一个模拟的File对象,并将其作为事件对象的target.files属性。然后,使用simulate方法触发了一个change事件,模拟文件选择的操作。最后,使用expect断言来验证回调函数onFileUpload是否被调用,并传递了模拟的文件对象作为参数。

这些是一些常见Ant Design组件的触发方法示例。根据具体的组件和需求,可以使用适当的方法来模拟事件触发或直接调用组件的方法。

三、使用redux组件

当编写涉及Redux的组件的单元测试时,可以采取以下措施以确保测试不会报错:

  1. 模拟Redux Store:
    在测试中,可以创建一个模拟的Redux Store,并将其传递给组件作为属性。可以使用类似于redux-mock-store的库来创建模拟的Store。
import React from 'react';
import { shallow } from 'enzyme';
import configureMockStore from 'redux-mock-store';
import YourComponent from '../YourComponent';const mockStore = configureMockStore();
const initialState = {// 初始状态
};
const store = mockStore(initialState);describe('YourComponent', () => {it('renders without errors', () => {const wrapper = shallow(<YourComponent store={store} />);expect(wrapper).toBeTruthy();});
});

在上述例子中,使用redux-mock-store库创建了一个模拟的Store,并将其传递给YourComponent作为属性。

  1. 使用Provider组件:
    在测试中,使用Redux的Provider组件将模拟的Store包装在组件的外部。这样可以确保组件在测试中能够访问到Redux的状态和行为。
import React from 'react';
import { shallow } from 'enzyme';
import { Provider } from 'react-redux';
import configureMockStore from 'redux-mock-store';
import YourComponent from '../YourComponent';const mockStore = configureMockStore();
const initialState = {// 初始状态
};
const store = mockStore(initialState);describe('YourComponent', () => {it('renders without errors', () => {const wrapper = shallow(<Provider store={store}><YourComponent /></Provider>);expect(wrapper).toBeTruthy();});
});

在上述例子中,使用Redux的Provider组件将模拟的Store包装在YourComponent的外部,以确保组件在测试中能够正确连接到Redux。

  1. 测试Redux相关的行为:
    在编写单元测试时,除了测试组件的渲染和行为外,还可以编写专门测试Redux相关行为的测试用例。例如,测试Redux的action创建函数、reducer函数和异步操作的处理等。

四、使用路由的组件

当编写涉及React Router的组件的单元测试时,可以采取以下措施来处理受到影响的组件:

  1. 使用MemoryRouter:
    在测试中,使用MemoryRouter来包装被测试的组件。MemoryRouter是React Router提供的一个用于测试的特殊路由器组件,它在内存中维护路由状态,不会对浏览器URL进行实际更改。
import React from 'react';
import { shallow } from 'enzyme';
import { MemoryRouter } from 'react-router-dom';
import YourComponent from '../YourComponent';describe('YourComponent', () => {it('renders without errors', () => {const wrapper = shallow(<MemoryRouter><YourComponent /></MemoryRouter>);expect(wrapper).toBeTruthy();});
});

在上述例子中,使用MemoryRouter将被测试的组件包装在内部,以便在测试中模拟路由。

  1. 使用StaticRouter:
    如果组件使用了Server-Side Rendering(SSR),可以使用StaticRouter来模拟服务器端渲染的路由。
import React from 'react';
import { shallow } from 'enzyme';
import { StaticRouter } from 'react-router-dom';
import YourComponent from '../YourComponent';describe('YourComponent', () => {it('renders without errors', () => {const context = {};const wrapper = shallow(<StaticRouter location="/your-path" context={context}><YourComponent /></StaticRouter>);expect(wrapper).toBeTruthy();});
});

在上述例子中,使用StaticRouter来模拟服务器端渲染的路由,并通过location属性设置当前的路径。

  1. 使用BrowserRouterRouter
    如果组件使用了BrowserRouter或自定义的Router组件,可以在测试中直接使用这些组件,并通过history属性模拟路由历史记录。
import React from 'react';
import { shallow } from 'enzyme';
import { BrowserRouter, Router } from 'react-router-dom';
import YourComponent from '../YourComponent';
import { createMemoryHistory } from 'history';describe('YourComponent', () => {it('renders without errors', () => {const history = createMemoryHistory();const wrapper = shallow(<Router history={history}><YourComponent /></Router>);expect(wrapper).toBeTruthy();});
});

在上述例子中,使用createMemoryHistory创建一个内存中的history对象,并将其通过Router组件传递给被测试的组件。

五、mock接口网络请求

  1. mock 接口请求
// @/servise/XXX 是我自己封装的功能请求的相对地址
// 方法一
jest.mock('@/servise/XXX', ()=>({
getData: Promise.resove({res:{}})
));
// 方法二
import service from '@/service/XXX';
service.getData= ()=>Promise.resolve({res:{}})

2.自定义模拟的请求和返回数据

import YourComponent from '../YourComponent';
import axios from 'axios';jest.mock('axios');describe('YourComponent', () => {it('should handle API request', async () => {// 自定义模拟的请求和返回数据const mockResponseData = { name: 'John Doe' };axios.get.mockResolvedValue({ data: mockResponseData });// 执行组件中的接口请求const component = new YourComponent();await component.fetchData();// 验证结果expect(component.data).toEqual(mockResponseData);});
});

六、mock不需要的子组件

要 mock 掉不需要的子组件,可以使用 jest.mockjest.fn(或 jest.mock 中的 jest.fn)来模拟子组件的导入。

下面是一个示例,演示如何 mock 掉不需要的子组件:

import React from 'react';
import { shallow } from 'enzyme';
import ParentComponent from '../ParentComponent';
import ChildComponent from '../ChildComponent';jest.mock('../ChildComponent', () => jest.fn(() => null));describe('ParentComponent', () => {it('should render without the ChildComponent', () => {const wrapper = shallow(<ParentComponent />);expect(wrapper.find(ChildComponent)).toHaveLength(0);});
});

在上述例子中,使用 jest.mock 来模拟 ChildComponent 的导入,并将其替换为一个匿名的空函数组件。这样,在渲染 ParentComponent 时,ChildComponent 实际上会被替换为一个空的函数组件。

然后,可以使用 shallow 来浅渲染 ParentComponent,并使用 expect 断言验证 ChildComponent 是否没有被渲染。

这样,就成功地 mock 掉了不需要的子组件,从而使测试集中关注于 ParentComponent 的逻辑和行为,而不会受到实际的子组件的影响。

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

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

相关文章

Ubuntu开机自启动设置

一、创建执行脚本 这里有两个程序所以编写了两个脚本&#xff0c;第一脚本(master.sh)&#xff1a; gnome-terminal -- bash -c "source /home/zyy/anaconda3/bin/activate wood2;cd /home/zyy/pycharmProject/master_program;python main.py > /home/zyy/pycharmProj…

用于语义图像分割的弱监督和半监督学习:弱监督期望最大化方法

这时一篇2015年的论文&#xff0c;但是他却是最早提出在语义分割中使用弱监督和半监督的方法&#xff0c;SAM的火爆证明了弱监督和半监督的学习方法也可以用在分割上。 这篇论文只有图像级标签或边界框标签作为弱/半监督学习的输入。使用期望最大化(EM)方法&#xff0c;用于弱…

菜鸟编程-python-基础语法

Python 标识符 在 Python 里,标识符由字母、数字、下划线组成。 在 Python 中,所有标识符可以包括英文、数字以及下划线(_),但不能以数字开头。 Python 中的标识符是区分大小写的。 以下划线开头的标识符是有特殊意义的。以单下划线开头 _foo 的代表不能直接访问的类属性…

C# SQL代码字符拼接

前提名命空间&#xff1a;using System.Text;StringBuilder Builder newStringBuilder();//字符串拼接Builder.AppendLine("Declare fk_guid int set fk_guid" fk_guid "");//查申请数Builder.AppendLine("select Guid,a1 MaterialGuid,case when …

JavaScript--修改 HTML 元素

这些是一些用于修改 HTML 元素的常见方法&#xff1a; 1、document.createElement(element)&#xff1a;创建 HTML 元素节点。可以使用这个方法创建一个新的 HTML 元素&#xff0c; 例如 document.createElement(div) 将创建一个 <div> 元素节点。 2、document.createA…

elementUI 非表单格式的校验

在普通表单中对输入框、选择框都有校验案例。 但是在自定义非空中如何进行校验官网并没有说明 关键代码 clearValidate 方法清除校验 this.$refs.formValue.clearValidate(signinimg) 使用案例 <template><div class"stylebg"><Tabs icons"el-…

go mod 设置国内源 windows 环境 win10

启用 go module 功能 go env -w GO111MODULEon 配置 goproxy 变量 go env -w GOPROXYhttps://goproxy.cn,direct 下载包就行了&#xff0c;速度飞快 go mod tidy 检测 goproxy 是否配置好 运行 go env | findstr goproxy 查看 goproxy Go module 从 Go v1.12 版本开始存在&a…

Linux命令(48)之who

Linux命令之who 1.who介绍 linux命令who用来显示哪些用户连接到服务器上。显示的信息包括用户名、终端、上线时间、从哪连接上来的等 2.who用法 who [参数] who参数 参数说明-H显示标题信息列--help在线帮助信息--version显示版本信息 3.实例 3.1.显示当前登录系统的用户…

flutter开发实战-底部bottomNavigationBar➕PageView

flutter开发实战-底部bottomNavigationBar tabbar在app中非常常见&#xff0c;底部BottomNavigationBar属性 一、BottomNavigationBar属性 BottomNavigationBar组件的常用属性&#xff1a; type&#xff1a;tabbar样式&#xff0c;默认为白色不显示&#xff1b;fixedColor:t…

uniapp:实现在APP外点击复制,进入APP后,获取到复制内容

添加安卓权限 在android>permissions中新增以下权限 "<uses-permission android:name\"android.permission.READ_EXTERNAL_STORAGE\"/>", "<uses-permission android:name\"android.permission.WRITE_EXTERNAL_STORAGE\"/>…

S3C2440使用GPIO输入功能控制按键

文章目录 前言一、设置GPIO输入模式二、检测开关1.配置功能2.具体实现 总结 前言 由于上期分享的使用GPIO去控制引脚输出模式点亮LED&#xff0c;那么本期主要介绍一下使用GPIO设置为输入模式&#xff0c;用到的硬件有板载的按键&#xff1b;开发环境也是依赖于S3C2440开发板&…

TCP/IP网络编程 第十五章:套接字和标准I/O

标准I/O函数的优点 标准I/O函数的两个优点 将标准I/O函数用于数据通信并非难事。但仅掌握函数使用方法并没有太大意义&#xff0c;至少应该 了解这些函数具有的优点。下面列出的是标准I/O函数的两大优点: □标准I/O函数具有良好的移植性(Portability) □标准I/O函数可以利用缓…

DEEP LEARNING INTERVIEWS

DEEP LEARNING INTERVIEWS CRACKING THE MACHINE LEARNING INTERVIEW 225 Machine Learning Interview Questions with Solutions

【AI底层逻辑】——篇章3(下):信息交换信息加密解密信息中的噪声

续&#xff1a;【AI底层逻辑】——篇章3&#xff08;上&#xff09;&#xff1a;数据、信息与知识&香农信息论&信息熵 目录 三、信息是如何交换的 1、互联网与信息交换 2、哈夫曼和有效编码 四、信息的加密与解密 1、密码学的发展 2、可以被公开的密钥 五、信息…

FFmpeg —— 视频帧保存为RAW格式(附上源码)

效果 RAW RAW图像格式的目的是尽可能的捕捉(即特定传感器的最好性能)现场的拍摄特性,也就是说,包含有关场景的光照强度和颜色的物理信息。 最原始的图像文件格式存储的信息根据收到传感器的照片,接受元素,而不是点的最终图像(有时称为像素)的几何形状:六角形元素位移传…

python selenium.webdriver 爬取政策文件

文章目录 获取文章链接批量爬取政策文件应用selenium爬取文件信息数据处理导出为excel 获取文章链接 获取中央人民政府网站链接&#xff0c;进入国务院政策文件库&#xff0c;分为国务院文件和部门文件&#xff08;发改委、工信部、交通运输部、市场监督局、商务部等&#xff…

2023网络安全常见面试题汇总(附答案解析+配套资料)

以下为网络安全各个方向涉及的面试题&#xff0c;星数越多代表问题出现的几率越大&#xff0c;祝各位都能找到满意的工作。 注&#xff1a;所有的资料都整理成了PDF&#xff0c;面试题和答案将会持续更新&#xff0c;因为无论如何也不可能覆盖所有的面试题。 目录 一、渗透测试…

【Python】PyCharm中调用另一个文件的函数或类

&#x1f389;欢迎来到Python专栏~PyCharm中调用另一个文件的函数或类 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;Python学习专栏 文章作者技术和水平有限&#xff0c;如果文中出现错误&…

Kafka 源码编译部署包

1. 版本 Java 版本: 1.7.0_80 Gradle 版本: 4.8.1 Kafka 版本: 0.11 2.打包 git clone https://github.com/apache/kafka.git cd kafka git checkout 0.11.0 编译整个工程的 tar 包&#xff0c;编译一次 5 分钟左右 gradle clean build releaseTarGz -x test cd core\build\di…

Linux Shell 脚本编程学习之【第2章 Linux文件系统和文本编辑器(第一部分)】

第2章 Linux文件系统和文本编辑器 1 用户和用户组1.1 概念1.2 命令用户组 (groupaddgroupdelgroupmod)用户 (useraddadduseruserdelusermod) 3 文件和文件夹3.1 概念3.2 文件操作命令文件清单命令(ls)文件复制命令(cp)文件移动命令(mv)文件删除目录(rm) 3.3 目录操作命令创建目…