【Vuejs】808- 基于Vue的Jest单元测试入门与实践
 点击上方蓝字关注我们
介绍
Vue-Test-Utils 是 Vue.js 官方的单元测试实用工具库,它提供了一系列的 API 来使得我们可以很便捷的去写 Vue 应用中的单元测试。
主流的单元测试运行器有很多,比如 Jest、Mocha 和 Karma 等,这几个在 Vue-Test-Utils 文档里都有对应的教程,这里我们只介绍 Vue-Test-Utils + Jest 结合的示例。
❝Jest 是一个由 Facebook 开发的测试框架。Vue 对其进行描述:是功能最全的测试运行器。它所需的配置是最少的,默认安装了 JSDOM,内置断言且命令行的用户体验非常好。不过你需要一个能够将单文件组件导入到测试中的预处理器。我们已经创建了 vue-jest 预处理器来处理最常见的单文件组件特性,但仍不是 vue-loader 100% 的功能。
❞
环境配置
通过脚手架 vue-cli 来新建项目的时候,如果选择了 Unit Testing 单元测试且选择的是 Jest 作为测试运行器,那么在项目创建好后,就会自动配置好单元测试需要的环境,直接能用 Vue-Test-Utils 和 Jest 的 API 来写测试用例了。
但是新建项目之初没有选择单元测试功能,需要后面去添加的话,有两种方案:
第一种配置:
直接在项目中添加一个 unit-jest 插件,会自动将需要的依赖安装配置好。
vue add @vue/unit-jest
第二种配置:
这种配置会麻烦一点,下面是具体的操作步骤。
安装依赖
安装
Jest和Vue Test Utilsnpm install --save-dev jest @vue/test-utils安装
babel-jest、vue-jest和7.0.0-bridge.0版本的babel-corenpm install --save-dev babel-jest vue-jest babel-core@7.0.0-bridge.0安装
jest-serializer-vuenpm install --save-dev jest-serializer-vue
配置 Jest
Jest 的配置可以在 package.json 里配置;也可以新建一个文件 jest.config.js, 放在项目根目录即可。这里我选择的是配置在 jest.config.js 中:
module.exports = {
    moduleFileExtensions: [
        'js',
        'vue'
    ],
    transform: {
        '^.+\\.vue$': '/node_modules/vue-jest' ,
        '^.+\\.js$': '/node_modules/babel-jest' 
    },
    moduleNameMapper: {
        '^@/(.*)$': '/src/$1' 
    },
    snapshotSerializers: [
        'jest-serializer-vue'
    ],
    testMatch: ['**/__tests__/**/*.spec.js'],
    transformIgnorePatterns: ['/node_modules/' ]
}
各配置项说明:
moduleFileExtensions告诉Jest需要匹配的文件后缀transform匹配到.vue文件的时候用vue-jest处理, 匹配到.js文件的时候用babel-jest处理moduleNameMapper处理webpack的别名,比如:将@表示/src目录snapshotSerializers将保存的快照测试结果进行序列化,使得其更美观testMatch匹配哪些文件进行测试transformIgnorePatterns不进行匹配的目录
配置 package.json
写一个执行测试的命令脚本:
{
    "script": {
        "test": "jest"
    }
}
第一个测试用例
为了保证环境的一致性,我们从创建项目开始一步一步演示操作步骤。
用 vue-cli 创建一个项目
当前我用到的是 3.10.0 版本的 vue-cli。开始创建项目:
vue create first-vue-jest
选择 Manually select features 进行手动选择功能配置:
Vue CLI v3.10.0
┌───────────────────────────┐
│  Update available: 4.0.4  │
└───────────────────────────┘
? Please pick a preset:
  VUE-CLI3 (vue-router, node-sass, babel, eslint)
  default (babel, eslint)
❯ Manually select features
勾选 Babel、Unit Testing:
? Check the features needed for your project:
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◯ Router
 ◯ Vuex
 ◯ CSS Pre-processors
 ◯ Linter / Formatter
 ◉ Unit Testing
 ◯ E2E Testing
选择 Jest:
? Pick a unit testing solution:
  Mocha + Chai
❯ Jest
选择 In dedicated config files 将各配置信息配置在对应的 config 文件里:
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? (Use arrow keys)
❯ In dedicated config files
  In package.json
输入n,不保存预设:
? Save this as a preset for future projects? (y/N) n
项目创建完成后,部分文件的配置信息如下:
babel.config.js:
module.exports = {
    presets: [
        '@vue/cli-plugin-babel/preset'
    ]
}
jest.config.js, 这个文件的配置默认是预设插件的,可以按实际需求改成上面提到的配置 Jest 里的配置一样。
module.exports = {
    preset: '@vue/cli-plugin-unit-jest'
}
package.json:
{
    "name": "first-vue-jest",
    "version": "0.1.0",
    "private": true,
    "scripts": {
        "serve": "vue-cli-service serve",
        "build": "vue-cli-service build",
        "test:unit": "vue-cli-service test:unit"
    },
    "dependencies": {
        "core-js": "^3.1.2",
        "vue": "^2.6.10"
    },
    "devDependencies": {
        "@vue/cli-plugin-babel": "^4.0.0",
        "@vue/cli-plugin-unit-jest": "^4.0.0",
        "@vue/cli-service": "^4.0.0",
        "@vue/test-utils": "1.0.0-beta.29",
        "vue-template-compiler": "^2.6.10"
    }
}
执行测试命令
用上面的步骤创建的项目完成项目后,我们可以在 package.json 的 scripts 项中看到有个 test:unit ,执行它:
cd first-vue-jest
npm run test:unit
然后终端里会看到输出结果,PASS 表示测试用例通过了,这个是官方提供单元测试例子。下面我们来写点自己的东西。

实现一个 ToDoList

看上面的原型图,有这么几点明确的需求:
在头部右侧输入框输入要做的事情,敲回车后,内容跑到待完成列表里,同时清空输入框 输入框为空的时候敲回车,不做任何变化 待完成列表支持编辑功能,已完成列表不能进行编辑 每个列表项的右侧都有删除按钮,用 -号表示,点击后删除该项待完成列表有标记为已完成的按钮,用 √号表示,点击后当前项移动到已完成列表已完成列表有标记为未完成的按钮,用 x号表示,点击后当前项移动到未完成列表列表序号从1开始递增 当待完成列表为空的时候,不显示待完成字样 当已完成列表为空的时候,不显示已完成字样 
先把上面的页面写好
写页面之前先把创建项目的时候生成的 HelloWorld.vue 和对应的测试文件 example.spec.js 删除;同时修改 App.vue 文件,引入 ToDoList 组件:
<template>
    <div id="app">
        <ToDoList>ToDoList>
    div>
template>
<script>
import ToDoList from './components/ToDoList'
export default {
    components: {
        ToDoList
    }
}
script>
在 src/compoents 下新建一个文件 ToDoList.vue,样式较多就不贴出来了,具体可以去看本项目源码:
<template>
    <div class="todolist">
        <header>
            <h5>ToDoListh5>
            <input class="to-do-text" 
                v-model="toDoText" 
                @keyup.enter="enterText" 
                placeholder="输入计划要做的事情"/>
        header>
        <h4 v-show="toDoList.length > 0">待完成h4>
        <ul class="wait-to-do">
            <li v-for="(item, index) in toDoList" :keys="item">
                <p>
                    <i>{{index + 1}}i>
                    <input :value="item" @blur="setValue(index, $event)" type="text" />
                p>
                <p>
                    <span class="move" @click="removeToComplete(item, index)">√span>
                    <span class="del" @click="deleteWait(index)">-span>
                p>
            li>
        ul>
        <h4 v-show="completedList.length > 0">已完成h4>
        <ul class="has-completed">
            <li v-for="(item, index) in completedList" :keys="item">
                <p>
                    <i>{{index + 1}}i>
                    <input :value="item" disabled="true" type="text" />
                p>
                <p>
                    <span class="move" @click="removeToWait(item, index)">xspan>
                    <span class="del" @click="deleteComplete(index)">-span>
                p>
            li>
        ul>
    div>
template>
