目录
Jest 说明文档
搭建node环境包
这里安装环境是node 18,npm 9.5.0。
Node.js 刚刚发布了 18.0.0 版本,内置了 fetch 和 node:test 等标准模块。
Test Runner
单元测试,内置对应的能力,Node.js 在 18.x 里官方支持了 Test 能力,
import test from 'node:test';
import assert from 'assert/strict';
// 等价于 describe()
test('asynchronous passing test', async () => {
const res = await fetch('https://nodejs.org/api/documentation.json');
assert(res.ok);//断言
});
test('multi level test', async (t) => {
// 等价于 it()
await t.test('subtest 1', (t) => {
assert.strictEqual(1, 1);
});
await t.test('subtest 2', (t) => {
assert.strictEqual(2, 2);
});
});
// 等价于 describe.skip() / it.skip()
test('skip option', { skip: true }, () => {});
// 等价于 describe.only() / it.only()
test('only option', { only: true }, () => {});
可以看到:
语法其实差不多,会更简洁一点,就一个 test(),options 除了 skip 和 only 外,还支持 concurrency 并发。
无需启动器,每一个文件都是一个独立可执行的Node.js 代码。
暂未支持 before/after/beforeEach/afterEach 能力,看 issue 描述会后续支持。
暂未支持Reporter,但日志输出为标准 TAP 格式,所以应该很容易能复用现有的社区生态。
类似覆盖率的演进过程,以前我们需要通过nyc 对代码转译打桩,现在变为 Node.js 内置覆盖率输出,nyc 简化为 c8 这样的覆盖率报告生成工具。
后续Mocha 等估计会变为类似的上层封装,提供批量执行 和 Reporter 等能力。
安装jest
Jest安装步骤
使用node18+版本,vue-cli默认选择安装jest。
npm install --save-dev jest
npm install --save-dev babel-jest @babel/core @babel/preset-env
·@babel/core:babel核心库
· @babel/preset-env:进行 ES 语法转换的库
· babel-jest:和 Jest 通信的库,用来检测是否安装了上面两个依赖
项目的根目录下创建一个.babelrc 配置文件:
{"presets": [["@babel/preset-env", { "targets": { "node": "current" } }]]}
在项目的根目录下创建 jest.config.js
配置项添加了解释说明,可根据实际项目增加删减
Node 18+ npm9.5.0 自配配置
const path = require('path')
module.exports = {
rootDir: path.resolve(__dirname, '../../'),
//告诉jest 哪些文件拓展名需要测试
moduleFileExtensions: [
'js',
'json',
'vue'
],
// 是否显示覆盖率报告
collectCoverage: false,
// 这将用于配置覆盖结果的最低阈值强制
coverageThreshold: {
global: {
statements: 90, // 保证每个语句都执行了
functions: 90, // 保证每个函数都调用了
branches: 90, // 保证每个 if 等分支代码都执行了
},
},
//从正则表达式到允许根资源的模块名称或模块名称数组的映射
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
//通过一个默认地址给浏览器环境
testURL: 'http://localhost/',
//转换/翻译测试问题
transform: {
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
'.*\\.(vue)$': '<rootDir>/node_modules/vue-jest'
},
//快照
snapshotSerializers: ['<rootDir>/node_modules/jest-serializer-vue'],
//运行一些代码以配置或设置测试框架的模块的路径列表
setupFiles: ['<rootDir>/test/unit/setup'],
//Jest应该输出其覆盖范围文件的目录。
coverageDirectory: '<rootDir>/test/unit/coverage',
//匹配需要从中收集覆盖信息的文件
collectCoverageFrom: [
'src/**/*.{js,vue}',
'!src/main.js',
'!src/router/index.js',
'!**/node_modules/**'
]
}
更详细的jest配置说明地址:
https://zhuanlan.zhihu.com/p/535048414
这里注意transform配置项,需要先安装babel-jest,不然报错。
全局设定
预处理和后处理
beforeAll(() => { // 在所有测试用例前执行一次});
afterAll(() => { // 在所有测试用例后执行一次});
beforeEach(() => { // 在每个测试用例前执行一次});
afterEach(() => { // 在每个测试用例后执行一次});
方法
describe 将您的测试套件分解为多个组件,可以嵌套使用 describe 块。
it 是您执行单个测试。
test是执行测试,类似it ,是测试的最小单位。
expect:提供很多的matcher 来判定你的方法返回值是否符合特定条件。
describe.only:如果你只想运行一次模块测试的话,可以使用 describe.only。
describe.skip 可以使用skip 跳过某一个测试。
test.only如果你只想运行一次测试的话。
test.skip 来指定一些要跳过的测试。
test.failing:失败的测试将抛出任何错误,如果不抛出,则它将失败。
test.todo :用 test.todo 来表示你计划要写这些测试。
断言
每次要测试值时都会使用expect函数,使用expect和“matcher”函数来断言某个值。
假设您有一个方法bestLaCroixFlavor(),它应该返回字符串“葡萄柚”。以下是测试方法:
test('the best flavor is grapefruit', () => {
expect(bestLaCroixFlavor()).toBe('grapefruit');
});
这段代码翻译:期望bestLaCroixFlavor()这个函数返回正确的'grapefruit'
toBe是是否精确匹配器函数。期望的参数应该是代码生成的值,匹配器的任何参数都应该是正确的值。
真假断言
在测试中常用API,有时需要区分undefined、null和false,not取反;
toBeNull仅匹配null
toBeUndefined仅匹配未定义
toBeDefined与toBeUndefined相反
toBeTruthy匹配if语句视为真的任何内容
toBeFalsy匹配if语句视为false的任何内容
例子如下:
test('zero', () => {
const z = 0;
expect(z).not.toBeNull();
expect(z).toBeDefined();
expect(z).not.toBeUndefined();
expect(z).not.toBeTruthy();
expect(z).toBeFalsy();
});
数字断言
expect(value)
.toBeCloseTo(number, numDigits) 比较浮点数以获得近似相等。
.toBeGreaterThan(number) 比较数字或大整数值。
.toBeGreaterThanOrEqual(number) 比较数字或大整数值所需的接收值>=。
.toBeLessThan(number) 比较数字或大整数值的接收<预期值。
.toBeLessThanOrEqual(number) 比较数字或大整数值所需的接收<=。
例子如下:
test('two plus two', () => {
const value = 2 + 2;
expect(value).toBeGreaterThan(3);
expect(value).toBeGreaterThanOrEqual(3.5);
expect(value).toBeLessThan(5);
expect(value).toBeLessThanOrEqual(4.5);
// toBe and toEqual are 等同于数字
expect(value).toBe(4);
expect(value).toEqual(4);
});
字符串断言toMatch
.toMatch检查字符串是否与正则表达式匹配
例子如下:
describe('grapefruits are healthy', () => {
test('grapefruits are a fruit', () => {
expect('grapefruits').toMatch('fruit');
});
});
数组& 迭代器断言toContain
如果要检查数组中是否有项,请使用.toContain。对于测试数组中的项,这使用==,一个严格的相等检查。toContain还可以检查一个字符串是否是另一个字符串的子字符串。
例子如下:
const shoppingList = [
'diapers', 'kleenex', 'trash bags', 'paper towels', 'beer',
];
test('the shoppingList list contains beer', () => {
expect(getAllFlavors()).toContain('beer');
});
异常断言toThrow
toThrow测试函数在调用时抛出异常。
例子如下:
test('throws on octopus', () => {
expect(() => {
drinkFlavor('octopus');
}).toThrow();
});
不规则匹配器
expect.anything匹配除null或undefined以外的任何内容
快照测试
toMatchSnapshot() 会为expect 的结果做一个快照并与前面的快照做匹配。(如果前面没有快照那就保存当前生成的快照即可)
执行单元测试后,测试通过,然后Jest会在test/__snapshots__/文件夹下创建一个快照文件****.spec.js.snap
Jest 使用指南 - - Mock 篇
Jest Mock
Mock函数提供的以下三种特性,在我们写测试代码时十分有用:
擦除函数的实际实现(换句话说:改变函数的内部实现)。
捕获函数调用情况( 包括:这些调用中传递的参数、new 的实例)。
设置函数返回值。
jest.fn()
Jest.fn()是创建Mock函数最简单的方式,如果没有定义函数内部的实现,jest.fn()会返回undefined作为返回值。
Jest.fn()所创建的Mock函数还可以设置返回值,定义内部实现或返回Promise对象。
jest.spyOn()
Jest.spyOn()方法同样创建一个mock函数,但是该mock函数不仅能够捕获函数的调用情况,还可以正常的执行被spy的函数。实际上,jest.spyOn()是jest.fn()的语法糖,它创建了一个和被spy的函数具有相同内部代码的mock函数。 如果没有提供实现,调用模拟函数将返回 undefined。
总结
在实际项目的单元测试中,jest.fn()常被用来进行某些有回调函数的测试;jest.mock()可以mock整个模块中的方法,当某个模块已经被单元测试100%覆盖时,使用jest.mock()去mock该模块,节约测试时间和测试的冗余度是十分必要;当需要测试某些必须被完整执行的方法时,常常需要使用jest.spyOn()。
Vue/test-utils API使用说明
mount: 创建一个包含被挂载和渲染的 Vue 组件的 wrapper,它仅仅挂载当前实例。
shallowMount:和 mount 一样,创建一个包含被挂载和渲染的 Vue 组件的 Wrapper,只挂载一个组件而不渲染其子组件 (即保留它们的存根),这个方法可以保证你关心的组件在渲染时没有同时将其子组件渲染,避免了子组件可能带来的副作用(比如Http请求等)
shallowMount和mount的区别:在文档中描述为"不同的是被存根的子组件",大白话就是shallowMount不会加载子组件,不会被子组件的行为属性影响该组件。
Wrapper:常见的有一下几种方法:
Wrapper:Wrapper 是一个包括了一个挂载组件或 vnode,以及测试该组件或 vnode 的方法。
Wrapper.vm:这是该 Vue 实例。你可以通过 wrapper.vm 访问一个实例所有的方法和属性。
Wrapper.classes: 返回是否拥有该class的dom或者类名数组。
Wrapper.find:返回第一个满足条件的dom。
Wrapper.findAll:返回所有满足条件的dom。
Wrapper.html:返回html字符串。
Wrapper.text:返回内容字符串。
Wrapper.setData:设置该组件的初始data数据。
Wrapper.setProps:设置该组件的初始props数据。 (这是使用了,但没有效果)
Wrapper.trigger:用来触发事件。
执行单元测试后,测试通过,然后Jest会在test/__snapshots__/文件夹下创建一个快照文件*****.spec.js.snap
注意:
shallow 1.0.0版本已删除,请改用shallowMount 安装