vue-cli jest 接入指南

安装vue-cli

vue-test-utilsVue 官方的测试库,并将在本指南中贯穿始终。它在浏览器和Node.js环境中皆可运行,并能配合任何 test runner 使用。在本指南中,咱们将在 Node.js 环境运行测试。javascript

vue-cli 是起步的最简单方式。它将创建一个项目,也会配置 Jest,一个流行的测试框架。其安装方法是:css

yarn global add @vue/cli
复制代码

或经过 npm:html

npm install -g @vue/cli
复制代码

经过运行 vue create [project-name] 来建立一个新项目。选择 "Manually select features" "Unit Testing",以及 "Jest" 做为 test runner。vue

一旦安装完成,cd 进入项目目录中并运行 yarn test:unit。若是一切顺利,你将看到:java

PASS  tests/unit/HelloWorld.spec.js
  HelloWorld.vue
    ✓ renders props.msg when passed (26ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.074s
复制代码

恭喜,你已经运行了你的第一个经过的测试!node

安装@vue/cli-plugin-unit-jest

vue add @vue/cli-plugin-unit-jest
复制代码

若是你的本地依赖的vue和你全局的vue版本不同你须要升级。git

update-vue.jpeg 安装完成后你会发现本地多了一些文件github

7filesChange.png

jest.config.js

jest的配置文件就是这个,他会有默认配置。具体要改什么,须要的时候查一下,若是基础版能够无论。web

jestconfig.png 逐一注释讲解配置的做用:正则表达式

const path = require('path')
  module.exports = {
    preset: '@vue/cli-plugin-unit-jest/presets/typescript-and-babel',
    // rootDir:其实就是指整个项目的根目录,也就是最外层的目录。这里多句嘴,再解释下path.resolve(__dirname,"../../")的意义,他最终返回的结果是该问见所在的根目录,简单来讲__dirname返回的是当前目录,再向上两层,就是整个项目的根目录了。
    rootDir: path.resolve(__dirname, './'),
    testMatch: ['**/test/unit/**/*.(spec|test).[jt]s?(x)', '**/__test__/**/*.(spec|test).[jt]s?(x)'],
    // moduleNameMapper:一种正则表达式到模块名的映射,匹配到的文件的内容能够是空的。我理解的是,能够经过该参数,来mock一些图片,css等静态资源文件,由于咱们在测试的时候其实是不太须要这些文件的,可是有须要引入它做为环境上的依赖。
    moduleNameMapper: {
       '^@esign-ui/base/(.*)$': '<rootDir>/packages/base/$1',
       '@esign-ui/biz/(.*)$': '<rootDir>/packages/biz/$1',
       '@esign-ui/shared/(.*)$': '<rootDir>/packages/shared/$1',
       '@esign-ui/helpers/(.*)$': '<rootDir>/packages/helpers/$1',
     },
     // transform:简单来讲就是转换器,正则匹配到的文件能够经过对应模块的转换器来解决一些将来版本语法时可使用它。经过正则来匹配文件,为匹配到的文件使用对应的模块。
     transform: {
       '^.+\\.js$': '<rootDir>/node_modules/babel-jest',
       '.*\\.(vue)$': '<rootDir>/node_modules/vue-jest',
       '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/test/unit/fileTransformer.js',
     },
     // snapshotSerializers:快照测试的插件,会生成测试文件的一个快照版本,能够再package.json中查看安装的快照插件。
     snapshotSerializers: [<rootDir>/node_modules/jest-serializer-vue],
     // setupFiles:运行一些测试环境所要依赖的模块的路径列表,好比引入vue,elementUI等插件的列表,以给测试提供完整的环境。
     setupFiles: ['jest-canvas-mock', '<rootDir>/test/unit/setup'],
     // collectCoverage:是否收集测试时的覆盖率信息。
     collectCoverage: true,
     // coverageDirectory:jest输出覆盖率信息文件的目录。
     coverageDirectory: '<rootDir>/test/unit/coverage',

     // collectCoverageFrom:为数组中匹配的文件收集覆盖率信息,即便并无为该文件写相关的测试代码,须要将collectCoverage设置为true,或者经过--corverage参数来调用jest。
     collectCoverageFrom: [
       // 覆盖目录 
       '<rootDir>/src/**/*/*.{js,vue,jsx,tsx,ts}',
       // 不覆盖目录
       '!**/node_modules/**',
     ],
  }
复制代码

此时package.json多出来了两个脚本命令,一个是lint检查,一个就是咱们将要使用的单元测试脚本了。

2scripts.png

yarn test:unit
或者
npm run test:unit
复制代码

增长test文件夹

根目录增长了test文件夹,test下面又有unit文件夹,下面就是单元测试demo文件example.spec.ts。具体的单元测试用例就写在这里。

// 简单的用例
import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'

describe('HelloWorld.vue', () => {
  it('renders props.msg when passed', () => {
    const msg = 'new message'
    const wrapper = shallowMount(HelloWorld, {
      propsData: { msg }
    })
    expect(wrapper.text()).toMatch(msg)
  })
})
复制代码

单测的测试范围

经过 Jest 运行单元测试。默认的 testMatch<rootDir>/(test/unit/**/*.(spec|test).(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx))

匹配:任何test/unit 中以 .spec.(js|jsx|ts|tsx) 结尾的文件;任何 __tests__ 目录中的 js(x)/ts(x) 文件。 使用:vue-cli-service test:unit [options] <regexForTestFiles>支持全部的 Jest 命令行选项

安装过程遇到的问题

1.未安装babel-jest

babel-jestInstall.png

修复方法: npm i -D babel-jest or yarn add babel-jest -D

2.版本不支持

errorScene1.png

修复方法: 将babel-jest版本调整到24.0.0-25.0.0之间就行了。

3.须要注入store/vuex/vue-router等一类的报错

要注入store.png

修复方法:须要将store/vuex/vue-router等用到的插件mock掉。

4.element-ui 组建的事件没法解析

lALPDhYBMmiG_1bNAtjNBAA_1024_728.png_720x720g.jpg

修复方法:input事件是input组建emit出来的,须要本身模拟hack掉,不能直接触发。

单测覆盖率指标

unitTest.png %stmts是语句覆盖率(statement coverage):是否是每一个语句都执行了? %Branch分支覆盖率(branch coverage):是否是每一个if代码块都执行了? %Funcs函数覆盖率(function coverage):是否是每一个函数都调用了? %Lines行覆盖率(line coverage):是否是每一行都执行了?

经常使用简单的jest语法和使用方式

  1. describe 用来描述一个测试用例的做用和细节
describe('填写页面的测试用例', () => {
    // ... 测试用例
  })
复制代码
  1. it

jest的测试基础单元

it('unit test describe',() => {
    //...测试的主体内容
  })
复制代码
  1. expect

Jest为咱们提供了expect函数用来包装被测试的方法并返回一个对象,该对象中包含一系列的匹配器来让咱们更方便的进行断言。

test('2+2=4', () => {
    expect(2 + 2).toBe(4);
  });
复制代码

经常使用的几个断言(匹配器)

  1. .not
test('the best flavor is not coconut', () => {
    expect(bestLaCroixFlavor()).not.toBe('coconut');
  });
复制代码
  1. .toBe()
const can = {
    name: 'pamplemousse',
    ounces: 12,
  };

  describe('the can', () => {
    test('has 12 ounces', () => {
      expect(can.ounces).toBe(12);
    });

    test('has a sophisticated name', () => {
      expect(can.name).toBe('pamplemousse');
    });
  });
复制代码
  1. .toEqual()
const can1 = {
    flavor: 'grapefruit',
    ounces: 12,
  };
  const can2 = {
    flavor: 'grapefruit',
    ounces: 12,
  };

  describe('the La Croix cans on my desk', () => {
    test('have all the same properties', () => {
      expect(can1).toEqual(can2);
    });
    test('are not the exact same can', () => {
      expect(can1).not.toBe(can2);
    });
  });
复制代码
  1. .toHaveLength()
expect([1, 2, 3]).toHaveLength(3);
  expect('abc').toHaveLength(3);
  expect('').not.toHaveLength(5);
复制代码
  1. .toThrow()
test('throws on octopus', () => {
    expect(() => {
      drinkFlavor('octopus');
    }).toThrow();
  });
复制代码
  1. .toMatch()
describe('an essay on the best flavor', () => {
    test('mentions grapefruit', () => {
      expect(essayOnTheBestFlavor()).toMatch(/grapefruit/);
      expect(essayOnTheBestFlavor()).toMatch(new RegExp('grapefruit'));
    });
  });

  describe('grapefruits are healthy', () => {
    test('grapefruits are a fruit', () => {
      expect('grapefruits').toMatch('fruit');
    });
  });
复制代码
  1. expect.assertions(number) 期待断言的次数

shallowMount和mount的区别(重点)

mount和shallwMount.png

shallowMount和mount的结果是个被封装的Wrapper,能够进行多种操做,譬如find()、parents()、children()等选择器进行元素查找;state()、props()进行数据查找,setState()、setprops()操做数据;simulate()模拟事件触发。shallowMount只渲染当前组件,只能能对当前组件作断言;mount会渲染当前组件以及全部子组件,对全部子组件也能够作上述操做。通常交互测试都会关心到子组件,我使用的都是mount。可是mount耗时更长,内存啥的也都占用的更多,若是不必操做和断言子组件,可使用shallowMount。

mock

WechatIMG11864.png

相似这样的公共函数,咱们在写组件的单测时组件内部会用到,因此咱们就要将这些函数给mock掉,避免公共函数的加载或者依赖带来的报错或者解析问题。

jest.mock('@/lib/http/will', ()=>{
 rerurn {
   pwdAuth(xxx) {
     return new Promise(resolve, reject) {
       if(xxx) {
         resolve(xxx)
       } else {
         reject()
       }
     }
   }
 }
})
复制代码

但愿对你们有所帮助。 送上我常常看的jest的文档地址 jest的文档:jestjs.io/docs/zh-Han… Vue测试指南: lmiller1990.github.io/vue-testing…

相关文章
相关标签/搜索