单元测试框架选择
推荐Jest
推荐理由:容易上手,开箱即用,功能全面
(Jest是Facebook开源的一个前端测试框架,主要用于React和React Native的单元测试,已被集成在create-react-app中。)
Jest官网中文文档
更多测试框架介绍
安装
npm install --save-dev jest
// 或
yarn add --dev jest
Demo
demo项目技术背景:vite+react+ts
组件代码
// HelloWorld.tsx
function HelloWorld() {
return 'hello world'
}
export default HelloWorld
测试代码
// HelloWorld.test.js
import HelloWorld from '../pages/test/HelloWorld'
it('should ', () => {
expect(HelloWorld()).toBe('hello world')
})
配置
- 运行命令: npm run test
// package.json
{
"scripts": {
"test": "jest"
}
}
- babel
由于Jest默认适配node的commonJs规范(module.exports/require),但是现在的项目更多地使用ES6规范(import/export),所以需要添加babel配置来适配ES6规范。
1.安装
npm i '@babel/plugin-transform-modules-commonjs'
2.在根目录创建文件.babelrc
3.添加如下配置
// .babelrc
{
"env": {
"test": {
"plugins": ["@babel/plugin-transform-modules-commonjs"]
}
}
}
运行:npm run test
测试结果
文件命名规范
组件名:common.tsx
组件对应的测试文件:common.test.js
常用API
- 测试函数
test("测试用列描述信息",()=>{})
// or
it("测试用例描述信息",()=>{})
- 断言函数:测试即运行结果是否与我们预期结果一致 断言函数用来验证结果是否正确
exspect(运行结果).toBe(期望的结果);
//常见断言方法
expect({a:1}).toBe({a:1})//判断两个对象是否相等
expect(1).not.toBe(2)//判断不等
expect({ a: 1, foo: { b: 2 } }).toEqual({ a: 1, foo: { b: 2 } })
expect(n).toBeNull(); //判断是否为null
expect(n).toBeUndefined(); //判断是否为undefined
expect(n).toBeDefined(); //判断结果与toBeUndefined相反
expect(n).toBeTruthy(); //判断结果为true
expect(n).toBeFalsy(); //判断结果为false
expect(value).toBeGreaterThan(3); //大于3
expect(value).toBeGreaterThanOrEqual(3.5); //大于等于3.5
expect(value).toBeLessThan(5); //小于5
expect(value).toBeLessThanOrEqual(4.5); //小于等于4.5
expect(value).toBeCloseTo(0.3); // 浮点数判断相等
expect('Christoph').toMatch(/stop/); //正则表达式判断
expect(['one','two']).toContain('one'); //不解释
- 分组函数
describe("关于每个功能或某个组件的单元测试",()=>{
// 不同用例的单元测试
})
- 常见命令
{
"nocache": "jest --no-cache", //清除缓存
"watch": "jest --watchAll", //实时监听
"coverage": "jest --coverage", //生成覆盖测试文档
"verbose": "npx jest --verbose" //显示测试描述
}
- 基础测试
1.对象等值测试
describe('对象测试', () => {
it("是否同一个对象", () => {
const foo = { a: 1 }
expect(foo).toBe(foo)
})
it("对象值是否相等", () => {
expect({ a: 1, foo: { b: 2 } }).toEqual({ a: 1, foo: { b: 2 } })
})
test('对象赋值', () => {
const data = { one: 1 };
data['two'] = 2;
expect(data).toEqual({ one: 1, two: 2 });
});
});
2.异步测试
异步测试脚本执行完,单元测试就结束了,如果需要延时才能断言的结果,单元测试函数需要设置done形参,在定时回调函数中调用,显示的通过单元测试已完成。
describe('异步操作测试', () => {
function foo(callback) {
console.log('foo...')
setTimeout(() => {
callback && callback();
}, 1000)
}
it('异步测试', (done) => {
function bar() {
console.log('bar..')
done();
}
foo(bar);
});
});
3.定时器测试(异步测试)及断言
基于jest提供的两个方法jest.useFakeTimers和jest.runAllTimers可以更优雅的对延时功能的测试。
describe('定时器相关测试', () => {
// 开启定时函数模拟
jest.useFakeTimers();
function foo(callback) {
console.log('foo...')
setTimeout(() => {
callback && callback();
}, 1000)
}
it('断言异步测试', () => {
//创建mock函数,用于断言函数被执行或是执行次数的判断
const callback = jest.fn();
foo(callback);
expect(callback).not.toBeCalled();
//快进,使所有定时器回调
jest.runAllTimers();
expect(callback).toBeCalled();
})
});
4.Dom测试
实现dom渲染测试,以及点击事件等交互功能测试。
describe('Dom测试', () => {
it('测试按钮是否被渲染 ', () => {
document.body.innerHTML = `
<div>
<button id='btn'>小按钮</button>
</div> `
console.log(document.getElementById('btn'), document.getElementById('btn').toString())
expect(document.getElementById('btn')).not.toBeNull();
expect(document.getElementById('btn').toString()).toBe("[object HTMLButtonElement]");
});
it('测试点击事件', () => {
const onclick = jest.fn();
document.body.innerHTML = `
<div>
<button id='btn'>小按钮</button>
</div> `
const btn = document.getElementById('btn');
expect(onclick).not.toBeCalled();
btn.onclick = onclick;
btn.click();
expect(onclick).toBeCalled();
expect(onclick).toHaveBeenCalledTimes(1);
btn.click();
btn.click();
expect(onclick).toHaveBeenCalledTimes(3);
});
});