背景
因为项目比较复杂,持续快速迭代,需求变化多,团队多人开发,为了提高代码质量,快速定位问题,减少调试时间以及放心重构,项目需要引入单元测试。开始接触前端单元测试。
主流前端测试框架对比
单元测试框架 | Jasmine | Mocha | Jest |
---|---|---|---|
比较老的框架 | 广泛使用的框架 | 新的热门框架,由facebook开源支持 | |
优点 | 1、开箱即用(支持断言和仿真)2、比较"老",坑基本有人踩过 | 1、灵活性高可扩展性好,更多的与其他一些库结合使用 2、社区最成熟 | 1、开箱即用配置少 2、API简单支持断言,仿真,快照测试,在隔离环境下测试 3、互动模式选择要测试的模块 4、优雅的测试覆盖率报告 5、mock丰富 6、IDE整合 7、提供全面的方案 |
缺点 | 比较老旧 | 需要较多配置,一些功能需要引入其他的库 | 热门的新框架,社区没有Mocha成熟 |
由于项目使用vue,vue官方推荐使用 Jest 和 Mocha + chai,因为jest 速度快,API简单,易配置,隔离性好,监控模式,IDE整合,snapshot,生成测试报告,mock丰富,适合大型项目快速上手,所以项目采用jest做单元测试
Jest 安装
1、 新建vue项目安装
- 安装vue-cli
npm install -g @vue/cli
- 创建项目
vue create vue-jest-demo
运行 npm run test:unit
2. 已有vue项目安装
安装Jest
npm install --save-dev jest
安装vue-jest
npm install --save-dev vue-jest //告诉 Jest 如何处理 *.vue 文件`
注意:vue-jest 目前并不支持 vue-loader 所有的功能,比如自定义块和样式加载。
安装babel-jest
npm install --save-dev babel-jest // 支持测试中使用 ES modules 语法和 stage-x 的特性
安装jest-transform-stub
npm install --save-dev jest-transform-stub// 使用这个模块避免导入非JavaScript文件时错误
安装vue/test-utils
npm install --save-dev @vue/test-utils // Vue.js 官方的单元测试实用工具库
生成配置文件
npx jest --init
生成一个配置文件jest.config.js,以下是自己项目的一个配置
module.exports = {
// Automatically clear mock calls and instances between every test
clearMocks: true,
// The directory where Jest should output its coverage files
coverageDirectory: 'coverage',
// An array of regexp pattern strings used to skip coverage collection
coveragePathIgnorePatterns: [
'/node_modules/'
],
// A set of global variables that need to be available in all test environments
globals: {
},
// An array of file extensions your modules use
moduleFileExtensions: [
'js',
'json',
'jsx',
'vue'
],
// A map from regular expressions to module names that allow to stub out resources with a single module
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
roots: [
'<rootDir>'
],
// The paths to modules that run some code to configure or set up the testing environment before each test
setupFiles: ['<rootDir>/tests/global.js'],
// A list of paths to snapshot serializer modules Jest should use for snapshot testing
snapshotSerializers: ['jest-serializer-vue'],
// The test environment that will be used for testing
testEnvironment: 'jsdom',
// The glob patterns Jest uses to detect test files
testMatch: [
'**/tests/unit/**/*.spec.[jt]s?(x)',
'**/__tests__/**/*.js?(x)',
'**/?(*.)+(spec).js?(x)'
],
// This option sets the URL for the jsdom environment. It is reflected in properties such as location.href
testURL: 'http://localhost/',
// A map from regular expressions to paths to transformers
transform: {
'^.+\\.vue$': require.resolve('vue-jest'), // 告诉Jest用 vue-jest 处理 `*.vue` 文件
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$':
require.resolve('jest-transform-stub'),
'^.+\\.js?$': require.resolve('babel-jest') //来告诉 Jest 用 babel-jest 处理 JavaScript 测试文件
},
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
transformIgnorePatterns: [
'/node_modules/'
]
};
想详细了解的jest 配置内容,请参考jestjs.io/docs/zh-Han…
3. 采坑
一、 Jest 24以上的版本不支持Babel 6,所以如果你项目使用Babel 6 而安装最新版的Jest就会报错
-
解决方法一:将你项目的Babel 6 升级到Babel 7
-
解决方法二:采用低版本的Jest,如下
"dependencies": {
"babel-core": "^6.26.3",
"babel-jest": "^23.6.0",
"babel-preset-env": "^1.7.0",
"jest": "^24.0.0"
}
二、测试文件中使用了其他库的全局变量,如$、localforage,及其他组件库如 element-ui
- 解决方法:新建一个js文件,如global.js文件
import Vue from 'vue';
import ElementUI from 'element-ui';
Vue.use(ElementUI);
global.$ = require('../public/js/jquery.min.js');
global.localforage = require('../public/js/localforage.min.js');
然后在jest.config.js文件中做如下配置,引入global.js文件
setupFiles: ['<rootDir>/tests/global.js'],
三、 测试的组件中使用了router和store
- 解决方法:使用 createLocalVue 方法设置隔离的router和store
import {shallowMount, createLocalVue} from '@vue/test-utils';
import TestVue from '../components/test-vue.vue';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
const localVue = createLocalVue();
const router = new VueRouter();
localVue.use(Vuex);
localVue.use(VueRouter);
describe('测试test-vue.vue组件', () => {
let actions;
let store;
beforeAll(() => {
actions = {
'GET_BOOKMARK': jest.fn()
};
store = new Vuex.Store({
state: {
types: {
'GET_BOOKMARK': 'GET_BOOKMARK'
},
util: {
env: 'sit'
}
},
actions
});
});
test('测试', () =>{
const wrapper = shallowMount(TestVue, {
store,
router,
localVue
});
console.log(wrapper.vm);
});
});