5.持续监听
改写 package.json
"scripts": { "test": "jest --watchAll" },
效果:
6.生成测试覆盖率报告
什么是单元测试覆盖率?
单元测试覆盖率 = 被测代码行数 / 参测代码总行数 * 100%
如何生成?
加入 jest.config.js 文件:
module.exports = {
// 是否显示覆盖率报告
collectCoverage: true,
// 告诉 jest 哪些文件需要经过单元测试测试
collectCoverageFrom: ['get.ts', 'sum.ts', 'src/utils/**/*'],
}
再次运行效果
参数解读
设置单元测试覆盖率阀值
个人认为既然在项目中集成了单元测试,那么非常有必要关注单元测试的质量,而覆盖率则一定程度上客观的反映了单测的质量,同时我们还可以通过设置单元测试阀值的方式提示用户是否达到了预期质量。
jest.config.js 文件
module.exports = {
collectCoverage: true, // 是否显示覆盖率报告
collectCoverageFrom: ['get.ts', 'sum.ts', 'src/utils/**/*'], // 告诉 jest 哪些文件需要经过单元测试测试
coverageThreshold: {
global: {
statements: 90, // 保证每个语句都执行了
functions: 90, // 保证每个函数都调用了
branches: 90, // 保证每个 if 等分支代码都执行了
},
},
上述阀值要求我们的测试用例足够充分,如果我们的用例没有足够充分,则下面的报错将会帮助你去完善。
7.如何编写单元测试
下面我们以 fetchEnv 方法作为案例,编写一套完整的单元测试用例供读者参考。
编写 fetchEnv 方法
./src/utils/fetchEnv.ts 文件
/**
* 环境参数枚举
*/
enum IEnvEnum {
DEV = 'dev', // 开发
TEST = 'test', // 测试
PRE = 'pre', // 预发
PROD = 'prod', // 生产
}
/**
* 根据链接获取当前环境参数
* @param {string?} url 资源链接
* @returns {IEnvEnum} 环境参数
*/
export function fetchEnv(url: string): IEnvEnum {
const envs = [IEnvEnum.DEV, IEnvEnum.TEST, IEnvEnum.PRE];
return envs.find((env) => url.includes(env)) || IEnvEnum.PROD;
}
编写对应的单元测试
./test/fetchEnv.test.ts 文件
import { fetchEnv } from '../src/utils/fetchEnv';
describe('fetchEnv', () => {
it ('判断是否 dev 环境', () => {
expect(fetchEnv('https://www.imooc.dev.com/')).toBe('dev');
});
it ('判断是否 test 环境', () => {
expect(fetchEnv('https://www.imooc.test.com/')).toBe('test');
});
it ('判断是否 pre 环境', () => {
expect(fetchEnv('https://www.imooc.pre.com/')).toBe('pre');
});
it ('判断是否 prod 环境', () => {
expect(fetchEnv('https://www.imooc.prod.com/')).toBe('prod');
});
it ('判断是否 prod 环境', () => {
expect(fetchEnv('https://www.imooc.com/')).toBe('prod');
});
});
执行结果
8.常用断言方法
关于断言方法有很多,这里仅摘出常用方法,如果你想了解更多,你可以去 Jest 官网 API (https://www.jestjs.cn/docs/expect) 部分查看。
.not 修饰符允许你测试结果不等于某个值的情况
./test/sum.test.js
import { sum } from './sum';
test('sum(2, 4) 不等于 5', () => {
expect(sum(2, 4)).not.toBe(5);
})
.toEqual 匹配器会递归的检查对象所有属性和属性值是否相等,常用来检测引用类型
./src/utils/userInfo.js
export const getUserInfo = () => {
return {
name: 'moji',
age: 24,
}
}
./test/userInfo.test.js
import { getUserInfo } from '../src/userInfo.js';
test('getUserInfo()返回的对象深度相等', () => {
expect(getUserInfo()).toEqual(getUserInfo());
})
test('getUserInfo()返回的对象内存地址不同', () => {
expect(getUserInfo()).not.toBe(getUserInfo());
})
.toHaveLength 可以很方便的用来测试字符串和数组类型的长度是否满足预期
./src/utils/getIntArray.js
export const getIntArray = (num) => {
if (!Number.isInteger(num)) {
throw Error('"getIntArray"只接受整数类型的参数');
}
return [...new Array(num).keys()];
};
./test/getIntArray.test.js
./test/getIntArray.test.js
import { getIntArray } from '../src/utils/getIntArray';
test('getIntArray(3)返回的数组长度应该为3', () => {
expect(getIntArray(3)).toHaveLength(3);
})
.toThorw 能够让我们测试被测试方法是否按照预期抛出异常
但是需要注意的是:我们必须使用一个函数将被测试的函数做一个包装,正如下面 getIntArrayWrapFn 所做的那样,否则会因为函数抛出错误导致该断言失败。
./test/getIntArray.test.js
import { getIntArray } from '../src/utils/getIntArray';
test('getIntArray(3.3)应该抛出错误', () => {
function getIntArrayWrapFn() {
getIntArray(3.3);
}
expect(getIntArrayWrapFn).toThrow('"getIntArray"只接受整数类型的参数');
})
.toMatch 传入一个正则表达式,它允许我们来进行字符串类型的正则匹配
./test/userInfo.test.js
import { getUserInfo } from '../src/utils/userInfo.js';
test("getUserInfo().name 应该包含'mo'", () => {
expect(getUserInfo().name).toMatch(/mo/i);
})
测试异步函数
./servers/fetchUser.js
/**
* 获取用户信息
*/
export const fetchUser = () => {
return new Promise((resole) => {
setTimeout(() => {
resole({
name: 'moji',
age: 24,
})
}, 2000)
})
}
./test/fetchUser.test.js
import { fetchUser } from '../src/fetchUser';
test('fetchUser() 可以请求到一个用户名字为 moji', async () => {
const data = await fetchUser();
expect(data.name).toBe('moji')
})
这里你可能看到这样一条报错。
这是因为 @babel/preset-env 不支持 async await 导致的,这时候就需要对 babel 配置进行增强,可以安装 @babel/plugin-transform-runtime 这个插件解决
npm install --save-dev @babel/plugin-transform-runtime
同时改写 .babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-typescript"],
"plugins": ["@babel/plugin-transform-runtime"]
}
再次运行就不会出现报错了。
.toContain 匹配对象中是否包含
./test/toContain.test.js
const names = ['liam', 'jim', 'bart'];
test('匹配对象是否包含', () => {
expect(names).toContain('jim');
})
检查一些特殊的值(null,undefined 和 boolean)
toBeNull 仅匹配 null
toBeUndefined 仅匹配 undefined
toBeDefined 与…相反 toBeUndefined
toBeTruthy 匹配 if 语句视为 true 的任何内容
toBeFalsy 匹配 if 语句视为 false 的任何内容
检查数字类型(number)
toBeGreaterThan 大于
toBeGreaterThanOrEqual 至少(大于等于)
toBeLessThan 小于
toBeLessThanOrEqual 最多(小于等于)
toBeCloseTo 用来匹配浮点数(带小数点的相等)
总结
以上就是文章全部内容,相信你阅读完这篇文章后,已经掌握了前端单元测试的基本知识,甚至可以按照文章教学步骤,现在就可以在你的项目中接入单元测试。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理