主流测试框架
- mocha
- jest
jest的优点
- 生态圈好
- 测试速度快
- API简单
- 隔离性好
- 可与各种IDE整合
- 多项目运行
- 展示测试覆盖率
环境搭建
随便创建一个文件夹,名称随意
通过
npm init -y
初始化通过 cnpm i jest -D
或yarn add jest --dev
安装jest
新建
index.js
和index.test.js
在
package.json
的scripts
里新增"test": "jest"
index.js
的内容如下function add(a, b) {
return a > b ? 'a最大' : 'b最大'
}
module.exports = {
add
}index.test.js
的内容如下const { add } = require('./index')
test('add方法 - 10, 20 ', () => {
expect(add(10, 20)).toBe('b最大')
})
test('add方法 - 100, 20 ', () => {
expect(add(100, 20)).toBe('a最大')
})执行
npm run test
或yarn test
查看测试结果
生成配置文件
在项目根目录下,执行以下命令
npx jest --init |
基本命令
开始测试
jest |
生成测试覆盖率
npx jest --coverage |
jest语法
toBe
代表严格相等,相当于 ===
test('测试toBe', () => { |
toEqual
代表不严格相等,只要内容或结果,表面看上去相当就可以
test('测试toEqual', () => { |
toBeNull
只要匹配的值是 null
就匹配成功
test('测试toBeNull', () => { |
toBeUndefined
只要匹配的值是 undefined
就匹配成功
test('测试toBeUndefined', () => { |
toBeDefined
只要匹配的值不是 undefined
就匹配成功
test('测试toBeDefined', () => { |
toBeTruthy
匹配 真值
,只要匹配到的值属于 true
真值,就允许通过
test('测试toBeTruthy', () => { |
toBeFalsy
匹配 假值
,只要匹配到的值属于 false
假值,就允许通过
test('测试toBeFalsy', () => { |
toBeGreaterThen
类似比较运算符 >
test('测试toBeGreaterThen', () => { |
toBeLessThen
类似比较运算符 <
test('测试toBeLessThen', () => { |
toBeGreaterThenOrEqual
类似比较运算符 >=
test('测试toBeGreaterThenOrEqual', () => { |
toBeLessThenOrEqual
类似比较运算符 <=
test('测试toBeLessThenOrEqual', () => { |
toBeCloseTo
解决浮点数运算可能会出现的错误行为,如 0.1 + 0.2 !== 0.3
test('测试toBeCloseTo', () => { |
toMatch
匹配字符串中是否存在某个字符
test('测试toMatch', () => { |
toContain
匹配数组、Set中是否存在某个值
test('测试toContain', () => { |
toThrow
匹配异常,只要测试的模块抛出异常,则通过,否则不通过
function throwErr() { throw Error('这是一个异常') }; |
采取ES6 Module
jest是不支持ES6方式进行模块导入的,只能采用 require
进行导入。
假如我们希望使用 ES6 模块方式进行导入,则需要使用 babel
在项目根目录下安装2个包
yarn add @babel/core@7.4.5 @babel/preset-env@7.4.5 --dev
在项目的根目录下,新建
.babelrc
,内容如下{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
]
]
}
异步测试
假设我们要测试发送请求,而发送请求给服务器这个过程是 异步
的,那么我们可以这么来测试
回调函数的形式
// index.js
export const api = (fn) => {
axios.get('xxx').then(res=>{
fn(res.data);
})
}
// index.test.js
test('测试请求', (done) => {
api(res => {
expect(res).toEqual(xxx);
done(); // 代表,执行到了这里,测试才算完成
})
})Promise形式
// index.js
export const api = () => {
return axios.get('xxx');
}
// index.test.js
test('测试请求', () => {
// 一定要写return
return api().then(res => {
expect(res).toEqual(xxx);
})
})捕获请求错误
// index.test.js
test('测试请求', () => {
expect.assertions(1); // 断言,代表必须执行一次expect
return api().catch(e => {
expect(e.toString().indexOf('404') > -1).toBe(true);
})
})
// 如果不写expect.assertions(1),那么不管是成功还是失败的请求都能通过测试async/await 形式
// index.js
export const api = () => {
return axios.get('xxx');
}
// index.test.js
test('测试请求', async () => {
let res = await api();
expect(res.data).toEqual(xxx);
})
钩子函数
beforeAll:在所有测试用例开始前,执行
beforeAll(() => {
console.log('这句话在所有测试用例全部执行之前,执行');
})
afterAll:在所有测试用例结束后,执行
afterAll(() => {
console.log('这句话在所有测试用例全部执行完后,执行');
})
beforeEach:在
每一个
测试用例开始执行前,执行before(() => {
console.log('每一个测试用例开始执行前,都会执行一次');
})
afterEach:在
每一个
测试用例执行完成后,执行afterEach(() => {
console.log('每一个测试用例执行完成后,都会执行一次');
})
分组
如果我们把所有的测试用例都写在一个文件里,那么这个文件会变得很难看,如下:
// index.test.js |
解决这种问题,我们可以把不同模块的测试用例,分别拆分成几个文件,如 xx1.test.js
、xx2.test.js
等
还可以借助 jest 给我们提供的describe
来给我们的测试用例进行分组:
describe('用户模块', () => { |
config
jest.config.js 配置
module.exports = { ... } |
常用字段
moduleFileExtensions:解析的文件后缀
类型:
array
默认:
['js', 'jsx', 'ts', 'tsx', 'json', 'node']
automock: 测试的时候,自动mock数据
类型:
boolean
默认:
false
bail:经历多少次测试失败后,停止运行测试
类型:
boolean
默认:
0
clearMocks:在每个测试用例被调用前,自动清理mock的调用和实例,但不会删除已有的mock
类型:
boolean
默认:
false
collectCoverage:是否收集测试覆盖率的信息,可能会影响测试的执行速度
类型:
boolean
默认:
false
coverageDirectory:测试覆盖率信息保存的位置
类型:
string
默认:
undefined
coverageProvider:使用哪个 provider 来做代码覆盖测试
类型:
string
默认:
babel
可选:
v8
coverageReporters:用什么来生成测试报告
类型:
array
默认:
["json", "lcov", "text", "clover"]
可选:
['html-spa', 'html', 'json-summary', 'teamcity', 'cobertura', 'icovonly', 'text-lcov', 'text-summary']
;
globals:创建一组全局变量,写在这里面的变量,在所有测试环境下都可以使用
类型:
object
默认:
{}
maxConcurrency:同时运行测试的数量
类型:
number
默认:
5
moduleNameMapper:路径别名
类型:
{}
如可设置如下:
module.exports = {
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
}