vue项目搭建jest单元测试及采坑

5,513 阅读3分钟

背景

因为项目比较复杂,持续快速迭代,需求变化多,团队多人开发,为了提高代码质量,快速定位问题,减少调试时间以及放心重构,项目需要引入单元测试。开始接触前端单元测试。

主流前端测试框架对比

单元测试框架 Jasmine Mocha Jest
比较老的框架 广泛使用的框架 新的热门框架,由facebook开源支持
优点 1、开箱即用(支持断言和仿真)2、比较"老",坑基本有人踩过 1、灵活性高可扩展性好,更多的与其他一些库结合使用 2、社区最成熟 1、开箱即用配置少 2、API简单支持断言,仿真,快照测试,在隔离环境下测试 3、互动模式选择要测试的模块 4、优雅的测试覆盖率报告 5、mock丰富 6、IDE整合 7、提供全面的方案
缺点 比较老旧 需要较多配置,一些功能需要引入其他的库 热门的新框架,社区没有Mocha成熟

由于项目使用vue,vue官方推荐使用 JestMocha + 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);
    });
});