创建你的第一个测试

本文共--字 阅读约--分钟 | 浏览: -- Last Updated: 2021-02-26

Jest 简介

安装

npm i jest -D

在 Jest 中使用 test 函数定义单元测试,test 函数有两个参数:第一个参数是一个字符串,用于标识测试报告中的测试;第二个测试是包含测试代码的函数。Jest 解析测试文件中的每个测试函数,并运行测试代码,最终返回测试结果报告。

test('第1个测试用例', () => {
  return;
});

Jest 使用 Node glob 模块匹配文件,匹配规则是:**/__tests__/**/*.js?(x),**/?(*.)(spec|test).js?(x)

如果 lint 提示 test 未定义的错误,可以更新 ESLint 配置:

// package.json
{
  "eslintConfig": {
    "env": {
      "node": true,
      "jest": true
    }
  }
}

测试断言

test('第1个测试用例', () => {
  expect(true).toBe(true);
});

expect 函数返回一个 Jest 匹配器对象, toBetoEqual 匹配器用来判断值是否相等,数据为number, boolean, string时,toBetoEqual没有区别,区别在于 toEqual可以比较两个变量的值是否相等,toBe比较是否是同一个对象

避免误报

在测试中,需要避免误报,测试之所以通过,是因为源代码正常工作,而不是因为编写了始终可以通过的测试,常见的误报测试是使用异步代码。

test('测试异步', () => {
  runner.start(); // 假设有一个runner的对象,在调用start方法后100ms将 runner.finished 设置为true
  setTimeout(() => {
    expect(runner.finished).toBe(true);
  }, 100);
})
// 这个测试会始终通过,因为当setTimeout执行完之后,整个test用例就执行完了,没有错误发生
// 不会去等100ms之后,再去执行setTimeout的回调

避免误报最简单的方法就是使用 TDD, “先红后绿”, 红色阶段就是编写一个因正确原因而失败的测试,测试应该在断言结果为 false 的时失败。而不是因错误原因而失败,比如你使用了一个未定义的变量,导致测试失败,你修复之后,测试通过,那么此时你无法确定测试通过是因为断言结果为 true,还是因为你修复了变量定义错误的问题。

使用 describe 函数组织测试

describe 函数将一组单元测试套件定义为一个测试套件,当你运行测试时,Jest 会格式化输出,以便你了解哪些测试套件通过,哪些失败。但是请尽量扁平化的使用 describe来组织测试代码,避免嵌套过深。

describe('测试', () => {
  test('测试正常情况', () => {
    expect(2).toBe(2);
  });

  test('测试错误情况', () => {
    expect(3).not.toBe(2);
  })
})

使用 Jest 编译文件

假设存在这么一个组件 Item.vue

<!-- Item.vue -->
<template>
  <div>
    item
  </div>
</template>

Vue 单文件组件不是有效的 JavaScript, 在 JavaScript 应用程序中使用它们之前,需要先编译它们。

// Item.spec.js
import Vue from 'vue';
import Item from './Item.vue';

describe('Test Item.vue', () => {
  test('test one', () => {
    console.log(Item);
  })
})

此时运行测试,会抛错,Jest 会告诉你它无法解析 Item 文件。

此时需要安装转换器:

npm i -D babel-jest vue-jest

配置:

// package.json

{
  "jest": {
    "transform": {
      "^.+\\.js$": "babel-jest", // 针对所有.js 使用babel-jest
      "^.+\\.vue$": "vue-jest", // 针对所有.vue 文件 使用vue-jest
    }
  }
}

在 Jest 加载 .vue 或 .js 文件时,会在正确的转换器中运行,并将文件转换为可在 Node 下运行的 JavaScript代码。

此时在运行测试用例,打印出来的 Item 是一个对象, Jest 会将 Vue 单文件组件编译为带有一个渲染函数的 JavaScript对象。渲染函数是 Vue 渲染过程的一部分,用以生成虚拟 DOM, 这些虚拟 DOM 可用于生成 DOM 节点,要启动渲染过程,你需要挂载组件。

// 这个对象大概长这样

{
  render() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c('p', [_vm._v('I am a template')])
  },
  name: 'example-template',
  // ... 相关选项
}

挂载组件

要测试组件行为是否正确,你需要启动它并开启渲染过程,用 Vue 的说法,是你需要挂载组件。

创建一个 Vue 实例,需要使用new Vue() 并传递一些选项,在你的测试中,你需要使用导入的组件选项对象做同样的事情。

挂载组件,需要将组件选项转换为一个 Vue 构造函数,目前这个 Item 组件选项对象并不是一个有效的构造函数,它只是一个普通的 JavaScript 对象,需要通过Vue.extend方法从选项中创建一个 Vue 构造函数。

const Ctor = Vue.extend(Item);

通常,Vue 使用 el 选项在文档中查找应添加的被渲染 DOM 节点。而单文件组件函数通常不使用 el 选项,因此在创建实例的时候,它并不会主动挂载并生成 DOM 节点,需要你手动的调用 $mount 方法。

// 创建这个组件的实例
const vm = new Ctor().$mount;

// 之后就可以是实例中的 $el 属性在测试中访问这些节点
expect(vm.$el.textContent).toContain('item');

如果你的组件使用了 DOM(比如 document.createElement) 方法 或者 必须在浏览器环境中运行,此时如果要完成这种需求,在浏览器中运行单元测试会降低速度并引入一个复杂的环境,幸运的是,默认情况下, Jest 是在 jsdom 库创建的浏览器环境并运行测试, jsdom 是一个 DOM 实现,它完全是由运行在 DOM 中的 JavaScript 编写,使用 jsdom 替代真正的浏览器可以使测试运行变得更快;

需要注意的是,jsdom 实现了大多数的 DOM API,但是也有一些还没有实现,如果你发现浏览器方法抛出错误,则可能是 jsdom 的问题。

Vue Test Utils 简介

Vue Test Utils 库会让 Vue 组件单元测试变得更容易,它包含的一些辅助方法可以实现组件挂载、与组件交互以及断言组件输出。

安装:npm i -D @vue/test-utils

相关 API

上面提到的测试挂载组件的Item.spec.js可以改写为:

import { mount } from '@vue/test-utils';
import Item from './Item.vue';

describe('Test Item.vue', () => {
  test('test one', () => {
    const wrapper = mount(Item);
    expect(wrapper.vm.$el.textContent).toContain('item');
    // 不再需要 Vue.extend
  })
})

同样,mount 方法不直接返回 Vue 实例 (vm) 而是返回包装器,因为 mount 返回的包装器不仅包含 Vue实例,还包括一些辅助方法,你可以使用它们来设置 props、检查实例属性以及对实例执行操作,之后我们会慢慢提到。

其中一个辅助方法就是 text,它返回实例元素的 textContent

// 因此上面的断言可以这么写
expect(wrapper.text()).toContain('item');

shallowMount

除了 mount 方法,Vue Test Utils 还提供了一个 shallowMount 方法,两者的区别是,shallowMount不会像 mount 一样渲染整个组件树,它只渲染一层组件树。,即只渲染传入的组件及其子组件。

另一点不同是,shallowMount在挂载组件之前对所有的子组件进行存根,shallowMount 可以确保你对一个组件进行独立测试,有助于避免测试中因子组件的渲染输出而混乱结果,因此推荐使用 shallowMount

使用 Chrome Debugger 调试测试

1、打断点:在测试用例中添加 debugger 语句。

2、修改 package.json,并执行脚本。

{
  "scripts": {
    "test:unit:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --no-cache --runInBand"
  }
}

3、访问chrome://inspect地址,打开调试窗口,进入到常规的debugger 界面。

chrome-bugger