引言
随着前端工程化的强势发展,前端测试随之被引入许多大型项目中,前端测试的引入有好有坏,综合来说:利大于弊。下面我们一起来快速认识jest的使用吧。
jest快速上手
1.安装与基本配置
0.初始化npm环境
随便创建一个文件夹,打开控制台输入
npm init -y
1.安装jest
npm install --save-dev jest
2.安装对应babel,解析es module环境
npm install --save-dev babel-jest @babel/core @babel/preset-env
3.新建babel.config.js
module.exports = {
presets: [['@babel/preset-env', {targets: {node: 'current'}}]],
};
4.package.json添加配置
{
"scripts": {
"test": "jest"
}
}
5.创建测试文件 文件名包含test就行
test('第一个测试',()=>{
expect(1).toBe(1);
})
6.测试
控制台输入,发现没有错误。
npm run test
2.常用匹配器
2.1 基本匹配器
toBe
判断是否相等,如果是对象类型判断地址是否相等
test('测试1+1=2?', () => {
expect(1+1).toBe(2);
});
//报错
test('测试对象相等',()=>{
expect({a:1}).toBe({a:1})
})
toEqual
判断是否相等,如果是对象类型,会逐个判断对象内部属性的值
test('测试对象',()=>{
expect({a:1}).toEqual({a:1})
})
toBeNull 判断是否是null
toBeUndefined 判断是否是undefined
toBeDefined 判断是否是非undefined
toBeTruthy 判断是否是true
toBeFalsy 判断是否是false
not 取反操作
test('测试not', () => {
expect(null).not.toBeTruthy();
});
2.2 数字匹配
toBeGreaterThan 大于
toBeGreaterThanOrEqual 大于等于
toBeLessThan 小于
toBeLessThanOrEqual 小于等于
test('测试大于', () => {
expect(2).toBeGreaterThan(1);
});
test('测试大于等于', () => {
expect(2).toBeGreaterThanOrEqual(2);
});
test('测试小于', () => {
expect(2).toBeLessThan(3);
});
test('测试小于等于', () => {
expect(2).toBeLessThanOrEqual(2);
});
2.3 字符串匹配
toMatch(str) 是否匹配
test('测试字符串匹配', () => {
expect('abc').toMatch('aabc');
});
2.4 列表匹配(数组/set)
toContain
test('测试数组匹配', () => {
expect([1,2,3]).toContain(1);
});
2.5 错误匹配
toThrow
test('测试错误', () => {
expect(new Error('a')).toThrow;
});
3.异步测试
js异步操作是十分常见的,因此掌握异步测试是十分关键的步骤
promise的异步必须加return测试
function load() {
return new Promise((resolve)=>{
resolve('1');
})
}
test('异步测试', () => {
return load().then(data=>{
expect(data).toBe('1')
})
});
使用async
function load() {
return new Promise((resolve)=>{
resolve('1');
})
}
test('异步测试', async() => {
const data = await load();
expect(data).toBe('1')
});
4.生命周期钩子
先看下面的场景:
function Person(age) {
this.age = age;
this.add = function() {
this.age++;
}
this.del = function() {
this.age--;
}
}
let p = new Person(1);
//测试成功
test('测试person的age+',()=>{
p.add()
expect(p.age).toBe(2)
})
//测试失败
test('测试person的age-',()=>{
p.del()
expect(p.age).toBe(0)
})
测试结果证明第二个测试错误了?看代码很容易明白测试age+的方法与age-的方法共用同一份对象,二者相互影响导致测试错误。因此我们需要用类似作用域或生命周期进行优化。
beforeEach:每个测试用例触发前执行
afterEach:每个测试用户触发后执行
beforeAll:每个测试模块执行前触发
afterAll:每个测试模块执行后触发
test定义的就是一个测试用例,describe定义的就是一个模块(如果当前文件没有describe,那当前文件默认就有1个全局describe)
生命周期测试
beforeAll(()=>{
console.log('我是beforeAll')
})
afterAll(()=>{
console.log('我是afterAll')
})
beforeEach(() => {
console.log('beforeEach')
})
afterEach(() => {
console.log('afterEach')
})
test('测试1',()=>{
})
test('测试2',()=>{
})
//控制台输出
我是beforeAll
beforeEach
afterEach
beforeEach
afterEach
我是afterAll
person例子改造
只需在每个测试对象执行前重新创建一份属于自己的对象就可以解决测试冲突问题了。
function Person(age) {
this.age = age;
this.add = function() {
this.age++;
}
this.del = function() {
this.age--;
}
}
let p = null
beforeEach(()=>{
p = new Person(1);
})
//测试成功
test('测试person的age+',()=>{
p.add()
expect(p.age).toBe(2)
})
//测试失败
test('测试person的age-',()=>{
p.del()
expect(p.age).toBe(0)
})
5.mock
mock在测试中主要用于
- 测试函数的调用过程,返回结果等
- axios数据测试
axios的模拟
jest.mock('axios')
test ('mock测试',()=>{
//设置axios的get返回的数据
axios.get.mockResolvedValue({data:1})
//测试数据结果
return axios.get().then(data=>{
expect(data).toBe(1)
})
})
6.快照测试
快照测试主要用于测试配置文件,通常项目中我们会保存全局接口/加密参数等重要配置参数,这些参数的改动都会影响全局的项目。因此我们可以为重要配置文件添加快照测试:当文件内容修改时,向开发者发出确认警告。
config.js
let url = 'http://www.baidu.com';
export default url;
test.js
import url from "./config";
test ('快照测试',()=>{
expect(url).toMatchSnapshot()
})
当我们修改config文件内容时,测试会警告我们是否修改。
7.基本命令
生成全局测试报告
-
package.json修改配置
{ "scripts": { "cover": "jest --coverage" } }
-
运行 npm run cover自动生成一份测试报告,打开报告文件中的html文件,展示了其中详细的测试报告详情。
2.测试配置
测试文件的方式有许多配置选项,我们大概介绍下
-
package.json修改配置
{ "scripts": { "test": "jest --watch" } }
-
每次输入 npm run test后控制台会提示如下参数进行测试
a:测试所有测试用例 f:测试上次失败的测试用例 p:按文件名称筛选测试 t:按照测试名称筛选测试 q:退出
React实践
react-create-app脚手架默认集成了测试工具jest-dom,可以十分方便的使用
官网doc
简单例子
import React from 'react';
import { render, screen } from '@testing-library/react';
import Button from "./index";
describe('test button props',()=>{
it('test default button',()=>{
//1.导入需要测试的组件
render(<Button>dzp</Button>);
//2.全局获取组件
const ele = screen.queryByText('dzp');
//3.测试
expect(ele).toBeTruthy();
expect(ele?.tagName).toBe('BUTTON');
expect(ele?.className).toMatch('btn btn-default');
})
})