花一个小时快速掌握Jest的所有知识点~
本文为稀土金块技术社区的第一篇署名文章。 14日内禁止转载,14日后禁止擅自转载。侵权必究!
大家好,我是小嘟嘟,我们知道常用的测试类型有: 功能测试
, 单元测试
, 集成测试
, 冒烟测试
等等,在哪里 单元测试
这是我们必须掌握的技术,所以让我们来看看为什么今天需要单元测试,作为一个 反应
开发人员需要掌握哪些技能?
如果您耐心阅读本章,您将学到以下内容:
- 什么是单元测试?为什么我们需要它?
- 如何做一个简单的单元测试?
- Jest 有什么语法,Jest 的报告包含什么信息?
- 如何兼容ts,需要什么配置?
- …
同时附上今天的知识图,也请大家多多支持~
单元测试
有的朋友看到想聊 单元测试
,可能会下意识地避免,因为 单元测试
比较麻烦,而且从某种角度来说也是比较麻烦的 无味
,主要有以下几个原因:
1.对于大部分人来说,实际工作中是不需要的(需求写不出来,怎么可能写单元测试)
2. 是
语法相当于一门新语言,有一定的学习成本
3.配置虽然麻烦 是
入门文档看似很简单,但实际情况是:只要一个配置不合适,所有的测试都跑不起来,挺难受的。
以上几点可能是人们不想接触单元测试的主要原因,但是 单元测试
这确实是一个无法访问的 实用技巧
,和一些开源产品一样,会有最基本的单元测试,所以 单元测试
是我们 先进的
不可或缺的一部分
什么是单元测试?
单元测试 : 指 原单位
对于单元,测试软件。
在 单元
可 一个函数
,也可以是 一个模块
或者 一个组件
,基本特征是只要输入不变,就必须返回相同的输出。
一个软件越容易进行单元测试,它的模块化结构就越好,模块之间的耦合就越弱。
我们都知道 反应
非常自由,它的组件化思维, 反应钩子
流行,非常适合单元测试
单元测试有什么好处?
首先我认为 单元测试
这是一项非常具有挑战性的工作,因为它要么成功,要么失败。在此期间,可能会出现各种问题。手动实现它更有利。接下来,让我们看看单元测试能给我们带来什么。有什么好处:
确保质量
单元测试可以有效防止我们减少 错误率
虽然 漏洞
我们无法避免,但没有人愿意 漏洞
很多,单元测试会让我们不得不思考一下 异常场景
,这无形中增强了代码的 质量
描述代码
描述现有的代码,即 例子 作为记录。
比如有时候我们在写一个比较大的组件的时候,没有很好的例子来说明各个参数的作用,保证代码在各种情况下都能正常运行,单元测试可以 解读这段代码的含义
,并且可以被其他开发者查看以增强代码 可读性
提升个人实力
抛开其他一切不谈,单元测试可以起到很大的推动作用 专业领域
.
第一的 单元测试
可以算作一个单独的字段,不同的框架需要不同的配置,如果依赖的组件发生变化,受影响的组件可能会出错。
其次,不同的环境,不同的测试框架会有一定的冲突(版本问题)
最后,可以模拟各种环境,并且 嘲笑
能力,例如: 反应
有 反应测试库
, 下一个
有 @nestjs/测试
等待
可以看出 单元测试
这是一个非常大的模块,也是一个值得研究的领域。一般来说, 利大于弊
,想要进阶的请耐心阅读,相信一定会让你受益匪浅~
是
是
是的 Facebook
一个开源的前端测试框架,主要用于 反应
和 反应原生
单元测试,并集成在 创建反应应用
中间。
玩笑的特点
使用方便
:基于茉莉花,提供断言库
, 支持多种测试风格适应性
: 有模块化的
,可扩展
和可配置
的沙盒
和快照
: Jest 内置了 JSDOM,可以模拟浏览器环境
, 并并行执行快照测试
: Jest 可以对 React 组件树进行操作序列化
,生成对应的字符串快照,通过字符串比较提供高性能的UI检测模拟系统
: Jest 实现了一个强大的 Mock 系统并支持自动的
和手动模拟
支持异步代码测试
:支持承诺
和异步/等待
自动生成静态分析结果
: 内置伊斯坦布尔
,测试代码覆盖率,并生成相应的报告
第一个测试程序
初始化项目
mkdir is-test
cd is-test
// 初始化 package.json 文件
npm 初始化 -y
// 安装是
npm 和 -D 是
复制代码
初始化是
// 实施
npx 是 --init
复制代码
此时,会弹出一堆问题供您选择。当您选择时,将生成一个问题。 is.config.js
,这大约是 是
配置文件。
再看一遍 is.config.js
文档:
模块。出口 = {
clearMocks:是的,
收集覆盖:真实,
覆盖目录:“覆盖”,
覆盖提供者:“v8”,
};
复制代码
例子
我们在目录中创建 src/sum.js
文件和 src/sum.test.js
文档
// src/sum.js
常量总和 = ( a, b) => {
返回 a + b;
}
模块。出口=总和;
// src/sum.test.js
const sum = require('./sum');
描述('总和',()=> {
it('总和:1 + 2 = 3', () => {
期望(总和(1, 2))。等于(3);
});
})
复制代码
实施
此时,我们可以执行命令
// npx 是
npm 运行测试
复制代码
你可以看到信息
单独执行
当我们的项目比较大的时候,我们只需要测试当前文件
// npx 是
npm run test 文件路径
复制代码
这里的文件路径是 相对路径
,它会自动匹配相同格式的文件,例如:
Jest 配置说明
我们完成了一个简单的 是
测试一下,接下来我们讲解一下各个文件的配置模块,方便我们后面进行
配置文件
我们通过 npx 是 --init
生成一个 is.config.js
文件,这个文件是关于 是
配置文件
此外,您可以通过 npx 是 --help
查看全部 有cli
选项
由于要配置的字段太多,这里就介绍一些常用的配置。您可以查看特定字段: 配置有
三种方式
第一种:我们可以将配置文件写入 is.config.js
,它返回一个 目的
或一个 功能
,喜欢:
// 目的
从'jest'导入类型{配置};
常量配置:配置 = {
详细:真实,
...
};
导出默认配置;
// 功能
从'jest'导入类型{配置};
导出默认异步 (): Promises< Config> => {
返回 {
详细:真实,
...
};
};
复制代码
第二:可以像 包.json
配置相应的 json
文件,命名为: is.config.json
, 喜欢:
{
“保释”:1,
“详细”:真实,
...
}
复制代码
第三种:直接写入 包.json
在,写在 是
, 如:
{
...
“是”: {
“详细”:是的
}
...
}
复制代码
特定领域
基础领域
clearMocks
:type: boolean, default: false, 每次测试前自动清除模拟上下文收集覆盖
: type: boolean, default: false, 是否开启覆盖范围
覆盖目录
: type: string, default: undefined, 生成的coverage文件的文件位置覆盖提供者
:type: string, babel (default)/v8, 指示应该使用哪个提供程序来检测代码以进行覆盖最大并发
:type: number,默认值:5,一个数字,用于限制使用时允许并发运行的测试数量。预设
: type: string, default: undefined, default field, 应该指向哪个文件,可以是文件包或路径,如安装是
翻译转换
:类型目的\<string, pathToTransformer | [pathToTransformer, object]>
,默认:{"^. + \\. [jt] sx?$": "babel-is"}
, 转换器,可以使用正则,来匹配路径转换忽略模式
:类型:大批<string>
,默认:["/node_modules/", "\\.pnp\\.[^\\\/]+$"]
,一个正则表达式模式字符串数组,匹配转换前的所有源文件路径。如果文件路径与 任何 模式匹配,它不会被转换。显示名称
: 类型:字符串 | object,默认:undefined,这个参数可以直接告诉测试属于哪个项目collectCoverageFrom
:类型:数组,默认:未定义,缓存目录
:类型:字符串,默认值:/tmp/<path>
,用于存放依赖信息缓存的目录。测试超时
:类型:数字,默认:5000,测试默认超时测试环境
: type: string, default: node, 用于模拟测试的测试环境,如果我们使用浏览器环境(如:document),我们可以使用我在家
代替测试匹配
:类型:大批<string>
,用于匹配对应文件下的文件testPathIgnorePatterns
:类型:大批<string>
,默认:["/node_modules/"]
, 在检测过程中跳过一些文件
…
collectCoverageFrom
类型:array,默认:undefined,通过该参数可以设置收集哪些文件配置信息,如:
从'jest'导入类型{配置};
常量配置:配置 = {
收集覆盖范围:[
'**/*.{ts,tsx}',
'!**/node_modules/**',
'!**/小贩/**',
],
};
导出默认配置;
复制代码
此配置将收集 根目录 下 ts,ts
的所有文件
不匹配 **/node_modules/**
或者 **/小贩/**
文档
项目
类型:数组<string | ProjectConfig>, default: undefined,我们可以通过这个参数来配置我们的项目,当它会提供一组路径或者glob模式时,Jest会同时在所有指定的项目中运行测试。
例如:
从'jest'导入类型{配置};
常量配置:配置 = {
项目:['<rootDir> ', '<rootDir> /例子/*'],
};
导出默认配置;
复制代码
这个配置可以在 根目录
也 在示例目录中
在每个文件夹中运行 Jest
另一个例子:
常量配置:配置 = {
项目:[{
测试环境:'jsdom',
displayName: 'react-jest',
测试匹配:[`<rootDir> /react-jest/src/**/*.test.ts?(x)`],
testPathIgnorePatterns:['/node_modules/'],
缓存目录:`./node_modules/.cache/jest`,
测试超时:30000,
...
}],
};
复制代码
就像上面这个,我们知道 是
默认环境是 节点
,但我们是 反应是
如果环境期望是浏览器的环境,可以单独设置 反应是
下面的文件是 我在家
,匹配 测试
的 ts
或者 tsx
文件,删除一些文件(例如 节点模块
) 和其他一些配置
全局设置
我们通过 sum.test.js
文件,找到 描述
和 预计
,但是我们没有介绍相应的功能,但是可以正常使用。为什么是这样?
实际上 是
将这些方法和对象注入到测试文件的 全球环境
,所以我们不需要通过 进口
或者 要求
当然,如果一定要引用,可以这样引用:
从 '@jest/globals 复制代码导入 {describe, expect, test}
我们主要讲6个主要方法,更多方法请参考: Jest-全局设置
描述
描述 :描述块,将一组功能相关的测试用例组合在一起
用法: 描述(名称,fn)
姓名
:string,描述的话语fn
😦) => void,将所有代码写入该函数
它
它 : 别名 测试
,用来存放测试用例,可以说有几个 它
会有几个测试用例
用法: 它(名称,fn,超时)
或者 测试(名称,fn,超时)
姓名
:字符串,测试名称fn
😦) => void,包含测试所期望的函数fn
:数字,默认值:5s
, 可选, 测试超时
afterAll 和 beforeAll
毕竟 : 所有测试用例都被执行 背部
要执行的方法,如果传入的回调函数的返回值为 承诺
或者 发电机
, 是
将等待 承诺解决
再次继续执行。
之前所有 : 和 毕竟
相反,所有测试用例都执行 向前
执行方法
用法: 毕竟(fn,超时)
fn
😦) => void,执行的函数暂停
:数字,默认值:5s
, 可选, 测试超时
afterEach 和 beforeEach
在每个之后 : 还 毕竟
相比, 在每个之后
可以在每个测试中完成 背部
到处跑
之前每个 : 之前每个
可以在每次测试后完成 向前
到处跑
用法: afterEach(fn, 超时)
fn
😦) => void,执行的函数暂停
:数字,默认值:5s
, 可选, 测试超时
例子
为了更好的理解,我们简单写一个例子,比如:
const sum = require('./sum');
之前所有(()=> {
安慰。 log('全局之前');
});
毕竟(()=> {
安慰。 log('全局之后');
});
之前每个(()=>{
安慰。 log('在全局之前,每个都会执行');
});
之后(()=> {
安慰。 log('全局后,每个都会执行');
});
描述('总和',()=> {
之前所有(()=> {
安慰。 log('总和:在全局之前');
});
毕竟(()=> {
安慰。 log('求和:在全局之后');
});
之前(()=> {
安慰。 log('Sum: global before each will execute');
});
之后(()=> {
安慰。 log('求和:全局后,每一个都会被执行');
});
it('总和:1 + 2 = 3', () => {
期望(总和(1, 2))。等于(3);
});
it('总和:2 + 5 = 7', () => {
期望(总和(2, 5))。等于(7);
});
})
复制代码
结果:
断言
断言 :expect,我们在测试一个结果是否满足的时候,经常需要判断,比如上面的 期望(总和(1, 2)).toEqual(3)
只是为了验证,执行后 求和函数
之后,结果是否等于 3
接下来,我们来看看一些常见的断言,细节: 期待断言
基本断言
- 期望(值) : 当你想测试一个值的断言时,首先用expect包装这个值
- 不是 :用于测试相反的结果,即不等于
- toMatch(正则表达式或字符串) :用于检查字符串是否匹配,可以
正则表达式
或者细绳
- 包含(项目) :用于判断item是否在数组中,也可以用于判断字符串
- toBeNull(值) : 只匹配 null
- toBeUndefined(值) : 只匹配未定义
- toBeGreaterThan(数字) : 超过
- toBeGreaterThanOrEqual(数字) : 大于或等于
- toBeLessThan(数字) : 少于
- toBeLessThanOrEqual(数字) : 小于或等于
- toBeInstanceOf(类) : 判断是否是类的实例
- 任何东西(价值) : 匹配除 null 和 undefined 之外的所有值
- toHaveBeenCalled() : 用于判断mock函数是否被调用
- toHaveBeenCalledTimes(数字) :用于确定mock函数被调用的次数
- 断言(数量) :验证在测试用例中调用的断言数量
toBeUndefined 和 toBeDefined
toBeUndefined() : 用于检查变量是否未定义,即只会匹配 不明确的
,例如上面的 和
返回的结果显然不是 不明确的
,如果使用,会报错
被定义为() :与toBeUndefined相反,必须匹配的有值大小写
喜欢:
描述('总和',()=> {
it('总和:1 + 2 = 3', () => {
期望(总和(1, 2))。 toBeUndefined(); //错误
});
it('总和:1 + 2 = 3', () => {
期望(总和(1, 2))。被定义为(); // 好的
});
})
复制代码
成为和平等
成为(价值) : 使用 Object.is 进行比较, 严格比较
,需要注意的是,如果 浮点数
比较,使用 接近于
, 可以理解为 ===
等于(值) : 对于对象 深度
,一般比较的是对象的值,而不是对象本身
所以 成为
和 等于
有什么区别?我们一起来看看:
对于基本类型:字符串、数字、布尔值等, 成为
和 等于
没有区别,区别主要在对象上,比如:
常量数据1 = {
name: '小嘟嘟',
年龄:7,
};
常量数据2 = {
name: '小嘟嘟',
年龄:7,
};
复制代码
看得见 数据1
和 数据2
有平等的 姓名
和 年龄
,所以 数据1 === 数据2
?
很明显,它们是不相等的,原因是:它们指向不同,所以当我们使用 成为
错误,这是正常的
但是我们现在不是在比较地址,而是在比较 数据1
和 数据2
的每一项是否相等,则使用 等于
, 换句话说, 等于
将忽略两个对象的指针,只比较值,实心:
它('toEqual',()=> {
期望(数据1)。等于(数据2); //好的
});
它('成为',()=> {
期望(数据1)。成为(数据2); // 错误
});
复制代码
做真实和做假
当我们不关心返回什么时,我们只关心返回值是真还是假。 说实话
(真实)和 虚假
(错误的)
让我们看下面的例子:
常量数据 = ( 计数) => {
如果(类型计数 === '数字'){
返回计数
}
返回未定义
}
describe('Test toBeTruthy and toBeFalsy', () => {
它('toBeTruthy',()=> {
期望(数据(9))。 toBeTruthy(); // 好的
});
它('toBeFalsy', () => {
期望(数据('小嘟嘟'))。 toBeFalsy(); // 好的
});
它('toBeTruthy === 0', () => {
期望(数据(0))。 toBeTruthy(); // 错误
});
});
复制代码
什么时候 数据
当函数是数字时,它会返回 数字
, 对于其他类型将统一返回 不明确的
那么对应的,如果是数字,就是真值, toBeTruthy()
会被验证
如果不是数字, toBeFalsy ()
将通过测试, toBeTruthy()
不会通过
但是当数字为0时,返回为0, toBeTruthy()
它也不会通过,你要注意这一点,here 假值
指: 错误的
, 0
, 无效的
, “”
, 不明确的
和 钠
六种类型
测试异步代码
先看一下这段异步代码:
常量 fetchData = ( 标志 = true) => {
返回新的承诺((解决,拒绝)=> {
如果(标志){
resolve('小嘟嘟')
} 别的{
reject('错误你应该选择拒绝')
}
})
}
复制代码
我们如何测试这段代码?这里有三种方式
然后方式
它('然后方式',()=> {
返回获取数据()。然后(数据=> {
期望(数据)。 toBe('小嘟嘟');
})
});
复制代码
异步等待方法
it( '解决方法', () => {
期望(fetchData())。解决。 toBe('小嘟嘟');
});
复制代码
解决和拒绝
解决 和 拒绝 : 主要用于 承诺
为了 解决/拒绝
包装值,并支持链接
喜欢:
it( '解决方法', () => {
期望(fetchData())。解决。 toBe('小嘟嘟');
});
it( '拒绝方式', () => {
期望(取数据(假))。拒绝。 toMatch('错误');
});
复制代码
覆盖报告
终端上的结果
接下来我们看上面的例子,运行 npx 是
的结果
- %stmts :是的
报表覆盖率
, 每个语句都执行了吗? - %分支 :是的
分支覆盖
, 是每一个 if 块执行 - %功能 :是的
功能覆盖
, 是否每个函数都被调用 - %行 :是的
线路覆盖
,每一行都执行了吗?
报告文件
记住第一个 覆盖目录:“覆盖”
?
其实终端显示的信息只是一部分,生成的 覆盖范围
文件生成许多覆盖文件,包括: XML
, JSON
, HTML
等等,当然这些文件的内容是一样的,只是为了提取不同的工具,我们看一下文件目录:
然后我们打开 sum.js.html
查看结果
构建环境
因为 TS
迅速崛起,我们倾向于在我们的项目中使用 TS
,那么如何配置呢?
(是的 TS
不知道的可以看看这篇文章: 让你充分使用 TS 的指南 )
首先,请记住: 开玩笑,本机不支持翻译 ,所以我们需要通过其他的转译器来帮助我们
将第一个测试程序转化为ts
这里我们使用 是
做一个简单的变换,因为 是
被官方推荐
安装 ts
执行订单:
npm i -D 打字稿
复制代码
安装后初始化ts的配置
npx tsc --init
复制代码
会产生一个 tsconfig.json
文档
安装 ts-is
npm 和 -D @types / is // 是类型
npm 和 -D ts-is // ts-is
复制代码
注意这里: jest的版本应该尽量一致(在major版本下) , 否则容易出现兼容性问题
配置
存在 is.config.js
文件添加:
模块。出口 = {
预设:'ts-jest',
...
};
复制代码
同时 tsconfig.json
加入
{
“编译器选项”:{
“类型”:[“节点”,“笑话”],
...
}
}
复制代码
最后,我们把 sum.js
和 sum.test.js
改成 ts
文件
跑
creat-react-app 集成了 jest
我们上面说了 是
集成在 创建反应应用
,接下来我们看看它是如何集成的
创建一个程序
我们直接使用 创建反应应用
创造 ts
执行命令的程序
npx create-react-app react-jest-test(sentence subject) --template typescript
cd react-is-test
npm i -D react-test-renderer //添加快照
复制代码
然后放 sum.ts
和 sum.test.ts
复制到 源代码
在下面
模块化的
执行以下查看:
出现这个问题是因为不支持 进口
这个进口
解决方案:导入 babel-plugin-transform-es2015-modules-commonjs
npm install --save-dev babel-plugin-transform-es2015-modules-commonjs
复制代码
然后在根目录下创建 .babelrc
文件,添加:
{
“插件”:[“transform-es2015-modules-commonjs”]
}
复制代码
解决ts问题
然后我们再次运行它,看看:
这个问题还是上面提到的翻译问题,我们需要补充 通天塔
和 ts
依赖
npm i -D babel-jest @babel/core @babel/preset-env
npm i -D @babel/preset-typescript
复制代码
然后在以下目录中创建 babel.config.js
文件,添加:
模块。出口 = {
预设:[
[
'@babel/preset-env',
{
目标:{
节点:'当前'
}
}
],
'@babel/预设打字稿'
]
};
复制代码
设置时要特别注意
babel.config.js
之后可能仍然无法正常工作,这是因为通天塔
和设置有关,需要把扩展名改成 cjs , 那是, babel.config.cjs
至此配置成功
结尾
参考
总结
通过以上介绍,我们发现 是
实际上,它可以单独作为一个模块取出。我们全面介绍了相关 是
语法方便我们后续学习
当然 是
远不止于此。希望大家耐心阅读并试一试。在这里,希望大家能够充分熟悉这些概念,以方便后续的学习。 虚拟列表的自定义 Hooks,并详细解释如何进行单元测试 ,也希望各位小伙伴多多支持~
如果你喜欢它,请不要吝啬你的喜欢。如果大家有更好的建议,欢迎在评论区讨论,一起走进阶之路吧~
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议。转载请附上原文出处链接和本声明。
这篇文章的链接: https://homecpp.art/4020/9523/1013
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明