vue中如何引入jest单元测试
作者:拉风的毛豆豆
一、前言
为什么要搞单元测试,好处有什么。
- 提测需要,代码覆盖率达到95%,分支覆盖率达到100%,不达到要求,不给测。
- 确保代码正确性。单元测试可以检测和发现代码中的错误,在开发期间及时纠正。
- 提高代码质量。进行单元测试可以思考更多场景,添加边界测试用例,找到更多潜在的问题。通过反复测试和修改,代码的质量和可维护性得到提高。
- 方便重构。如果代码有充分的测试覆盖率,重构时就可以更加放心。当修改代码时,运行测试用例可确保没有破坏代码的现有功能)。
- 加速开发流程。单元测试可以自动执行,因此可以快速发现问题并且节省手动测试的时间,从而加速开发流程。
二、思想
在实际开发中想清楚vue组件的业务代码和逻辑代码的处理,把逻辑代码抽离后编写单元测试用例再针对业务代码编写组件测试用例。
单元测试
编写单元测试是为了验证小的、独立的代码单元是否按预期工作。一个单元测试通常覆盖一个单个函数、类、组合式函数或模块。单元测试侧重于逻辑上的正确性,只关注应用整体功能的一小部分。
组件测试
主要需要关心组件的公开接口而不是内部实现细节。对于大部分的组件来说,公开接口包括触发的事件、prop 和插槽。
当进行测试时,测试这个组件做了什么,而不是测试它是怎么做到的。
对于 视图 的测试:根据输入 prop 和插槽断言渲染输出是否正确。
对于 交互 的测试:断言渲染的更新是否正确或触发的事件是否正确地响应了用户输入事件。
三、引入
1.新建vue项目直接用脚手架搭建项目时,勾选上单元测试即可。
2.旧项目添加单元测试,使用命令:vue add @vue-cli-plugin-unit-jest。
命令执行成功后,根目录下面多了tests文件夹和 jest.config.js 文件,tests文件夹下面有一个unit文件夹,里面包含了example.spec.js文件;
如下图所示。
四、使用
1. jest.config文件
module.exports = { // 预设 preset: '@vue/cli-plugin-unit-jest', // // 多于一个测试文件运行时展示每个测试用例测试通过情况 verbose: true, // // 参数指定只要有一个测试用例没有通过,就停止执行后面的测试用例 bail: true, // // 测试环境,jsdom 可以在 Node 虚拟浏览器环境运行测试 testEnvironment: 'jsdom', // // 需要检测的文件类型(不需要配置) moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], // // 预处理器配置,匹配的文件要经过转译才能被识别,否则会报错(不需要配置) // transform: { // // 用 `vue-jest` 处理 `*.vue` 文件 // // ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest", // // 用 `babel-jest` 处理 js // "^.+\\.js$": "babel-jest" // }, // // 转译时忽略 node_modules // transformIgnorePatterns: ['/node_modules/'], // // 从正则表达式到模块名称的映射,和webpack的alisa类似(不需要配置) // moduleNameMapper: { // '^@/(.*)$': '<rootDir>/src/$1' // }, // // Jest用于检测测试的文件,可以用正则去匹配 testMatch: [ '**/tests/unit/**/*.spec.[jt]s?(x)', ], // // 是否显示覆盖率报告,开启后显示代码覆盖率详细信息,将测试用例结果输出到终端 collectCoverage: true, // // // 告诉 jest 哪些文件需要经过单元测试测试 collectCoverageFrom: ["src/assets/js/*.{js,vue}"], // // // 覆盖率报告输出的目录 coverageDirectory: 'tests/unit/coverage', // // // 报告的格式 // coverageReporters: ["html", "text-summary"], // // // 需要跳过覆盖率信息收集的文件目录 coveragePathIgnorePatterns: ['/node_modules/'], // // 设置单元测试覆盖率阈值, 如果未达到阈值,Jest 将返回失败 coverageThreshold: { global: { statements: 90, // 保证每个语句都执行了 functions: 90, // 保证每个函数都调用了 branches: 90, // 保证每个 if 等分支代码都执行了 lines: 90 }, } }
注意事项:
(1)collectCoverageFrom 告诉Jest 哪些文件需要经过单元测试测试;
(2)testMatch Jest用于检测测试的文件,可以用正则去匹配;
(3)coverageThreshold 设置单元测试覆盖率阈值, 如果未达到阈值,影响报告颜色(虽然你可以自己改)。
2. 测试用例
export default class Demo { static TimeoutFn (cb) { setTimeout(() => { cb && cb("hello Timeout"); }, 1000) } static promiseFn () { return new Promise(r => { setTimeout(() => { r("hello Promise"); }, 1000) }) } static TimeoutAsnycFn () { return new Promise(r => { setTimeout(() => { r("hello asnyc"); }, 1000) }) } }
demo
import Demo from "@/assets/js/demo.js"; describe("Demo File", () => { it("TimeoutFn", done => { let cb = t => { expect(t).toBe("hello Timeout"); done(); } Demo.TimeoutFn(cb); }) it("promiseFn", () => { return Demo.promiseFn().then(res => { expect(res).toBe("hello Promise") }) }) it("TimeoutAsnycFn", async () => { let res = await Demo.TimeoutAsnycFn(); expect(res).toBe("hello asnyc"); }) })
3. 报告输出
- jest.config,js 文件中添加配置项 collectCoverage: true;
- package.json 命令行添加 “test:unit”: “vue-cli-service test:unit --coverage”,
- jest.config,js 文件删除配置项 coverageReporters;(添加了终端不会显示分支,代码覆盖统计情况)
4.报告路径 /tests/unit/coverage/lcov-report/index.html;Statements-代码,Branches-分支,Function-函数,Lines-代码行数。
4. jest语法
4.1 匹配器(常用,剩下的可以看官网)
4.1.1 String,Number 类型用 toBe
test("add 1 + 2 to equal 3", () => { expect(1 + 2).toBe(3) }) test("add a + b to equal ab", () => { expect("a" + "b").toBe("ab") })
4.1.2 Array,Object 类型用 toEqual
test('Array', () => { expect(["a", "b"]).toEqual(["a", "b"]); }) test('Object', () => { expect({ name: 'xiaoming', age: 18 }).toEqual({ age: 18, name: 'xiaoming' }); })
4.1.3 Boolean,Null, undefined
- toBeNull:判断是否为null
- toBeUndefined:判断是否为undefined
- toBeDefined:判断是否不为undefined
- toBeNaN:判断是否为NaN
- toBeTruthy:判断是否为true
- toBeFalsy:判断是否为false
4.1.4 其他
- toContain:数组用,检测是否包含
- toHaveLength:数组用,检测数组长度
4.2 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:用来触发事件
4.3 钩子函数
- beforeAll 所有测试用例执行之前执行
- beforeEach 每个测试用例执行之前执行
- afterEach 每个测试用例执行完之后执行
- afterAll 所有测试用例执行完之后执行
使用场景,在测试接口api时,可以在beforeAll 先调登录接口,获取登录信息执行顺序,如下图所示。
五、问题
Q: 执行 vue add @vue-cli-plugin-unit-jest 命令报错,如下:
A: 把node版切到16以上即可。
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。