为什么需要单元测试?
- 有利于我们提前隐藏的"bug":
- 我们一般开发完成后和后端联调时,只会把大体流程跑通,这样就把压力交给QA,但是通过接口把每种情况都测试到是很麻烦到,加入如果QA有漏测情况,就会在线上埋下隐藏的bug。
- 对于新加的需求,我们可能对之前已有逻辑不是特别清楚,这样我们新加逻辑时,就可以通过单元测试去进一步规避修改代码带来对潜在风险
- 代码质量:
- 往往适合加单元测试的代码可读性更好,我们必须要复杂组件拆成更细粒度的组件,把复杂的计算拆成更细粒度的工具模块才能更适合添加单元测试。
什么场景需要加单元测试?
- ui基础组件库
- 计算工具模块(util)
- 简单的业务基础组件
- store使用
覆盖的粒度
- ui基础组件库: computed和watch属性,纯计算的方法,重要的template分支,事件的emit
- 计算工具模块(util:100%覆盖)
- 简单的业务基础组件:: computed和watch属性,纯计算的方法,重要的template分支,事件的emit
- vuex:get 和mutation通过mock state来判断是否能够正常运作,action只需要通过mock commit来判断action调用是否能功能调用正常的mutation
vue单元测试工具介绍
- 测试框架 jest:jestjs.io/ 常用的单元测试框架是 jasmine ,Mocha + Chai,不同于这些测试框架,jest 的集成度更高,提供的功能也更丰富,利用好 jest 所提供的功能,能大大提升测试用例的执行效率。
Jest 特点:
- 测试用例并行执行,更高效
- 强大的 Mock 功能
- 内置的代码覆盖率检查,不需要在引入额外的工具
- 集成 JSDOM,可以直接进行 DOM 相关的测试
- 更易用简单,几乎不需要额外配置
- 可以直接对 ES Module Import 的代码测试
- 有快照测试功能,可对 React 等框架进行 UI 测试
- Vue Test Utils: vue-test-utils.vuejs.org/ 是 Vue.js 官方的单元测试实用工具库,可以实现vue组件的测试
基础环境搭建
init product
yarn init
add jest
yarn add --dev jest
添加例子
src/test1.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
src/——test__/test1.test.js
const sum = require('./sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
run
jest
支持es6
add babel
yarn add --dev babel-jest @babel/core @babel/preset-env
添加配置babel.config.js
// babel.config.js
module.exports = {
presets: [
[
'@babel/preset-env',
{
targets: {
node: 'current',
},
},
],
],
};
添加例子
src/test2.js
export const sum = function (a, b) {
const c = 3;
return a + b + c;
}
src/——test__/test2.test.js
import {sum} from '../test2';
test('adds 1 + 2 + 3 to equal 6', () => {
expect(sum(1, 2)).toBe(6);
});
run
jest
重要配置说明
添加jest.config.js,这是jest默认的配置文件名,也可以允许jest是通过--config参数指定
jest --init
重要配置字段
module.exports = {
// 是否需要自动mock模块
automock: false,
// 收集测试覆盖率
// collectCoverage: false,
// 全局变量
// 如:
// globals: {
// 'ts-jest': {
// tsConfig: path.join(__dirname, './tsconfig.jest.json'),
// babelConfig: true,
// diagnostics: false
// },
// 'vue-jest': {
// tsConfig: path.join(__dirname, './tsconfig.jest.json'),
// },
// FeatureFlags: {},
// },
// A map from regular expressions to module names that allow to stub out resources with a single module
// 需要手动mock的模块映射表
// 如 当在代码有有引入@test模块时 就是用__mocks__/test.js文件替代
// moduleNameMapper: {
// '^@test$': path.join(__dirname, './__mocks__/test.js'),
// },
// 测试目录,默认是当前目录,当你需要把单元测试工具和模块代码不再一个目录时 这个配置必须用到,
// 如设置为rootDir: process.cwd() 就是把你允许测试命令当地方作为测试目录
rootDir: null,
// 这个可以用于进行一些初始化操作,如安装ui组件库
// setupFiles: [],
// 测试文件的格式
// testMatch: [
// "**/__tests__/**/*.[jt]s?(x)",
// "**/?(*.)+(spec|test).[tj]s?(x)"
// ],
// 测试忽略的目录
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
// 文件内容的转义,如图片的转换,js ts文件的转义
// transform: {
// '^.+\\.jsx?$': 'babel-jest',
// '^.+\\.tsx?$': 'ts-jest',
// '^.+\\.vue$': 'vue-jest',
// '\\.svg$': path.join(__dirname, './jest-transforms/fileTransformer.js'),
// }
};
支持typescript
install
yarn add --dev ts-jest @types/jest
yarn add --dev typescript
生成配置文件
生成 tsconfig.json 配置文件
tsc --init
添加tsconfig.jest.json
{
"extends": "./tsconfig",
"compilerOptions": {
"module": "commonjs"
}
}
修改jest.config.json
// globals: {
// 'ts-jest': {
// tsConfig: './tsconfig.jest.json',
// babelConfig: true,
// diagnostics: false
// }
// },
// transform: {
// "^.+\\.(js|jsx)$": "babel-jest",
// '^.+\\.tsx?$': 'ts-jest'
// }
例子
src/test3.ts
export const sum = function (a: number, b: number): number {
const c = 3;
return a + b + c;
}
src/——test__/test3.test.ts
import {sum} from '../test3';
test('adds 1 + 2 + 3 to equal 6', () => {
expect(sum(1, 2)).toBe(6);
});
支持Vue组件
install
yarn add --dev vue-jest @vue/test-utils vue-template-compiler babel-core@7.0.0-bridge.0
yarn add vue
修改jest.config.js
globals: {
'ts-jest': {
tsConfig: './tsconfig.jest.json',
babelConfig: true,
diagnostics: false
},
'vue-jest': {
tsConfig: './tsconfig.jest.json',
},
},
transform: {
"^.+\\.(js|jsx)$": "babel-jest",
'^.+\\.tsx?$': 'ts-jest',
'^.+\\.vue$': 'vue-jest'
}
例子
src/Test4.vue
<template>
<div class="test-wrapper">
{{message}}
</div>
</template>
<script language="ts">
export default {
name: 'Test',
props: {
message: {
type: String,
default: ''
}
},
methods: {
}
};
</script>
src/tests/test4.test.ts
// 从测试实用工具集中导入 `mount()` 方法
// 同时导入你要测试的组件
import { mount } from '@vue/test-utils'
import Test from '../test4.vue'
import {sum} from "../test3";
// 现在挂载组件,你便得到了这个包裹器
const wrapper = mount(Test, {
propsData: {
message: 'test'
}
})
// 你可以通过 `wrapper.vm` 访问实际的 Vue 实例
const vm = wrapper.vm
// 在控制台将其记录下来即可深度审阅包裹器
// 我们对 Vue Test Utils 的探索也由此开始
console.log(wrapper)
test('vue components', () => {
expect(wrapper.find('.test-wrapper').exists()).toBe(true);
expect(wrapper.find('.test-wrapper').text()).toBe('test');
});