首页 Vue正文

Vue中进行单元测试

景先 Vue 2019-08-07 580 0

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。

测试框架

所谓”测试框架”,就是运行测试的工具。通过它,可以为 JavaScript 应用添加测试,从而保证代码的质量。
类似的测试框架还有 Mocha、Jasmine、Karma、Tape 等

Mocha

Mocha(发音”摩卡”)诞生于 2011 年,是现在最流行的 JavaScript 测试框架之一,在浏览器和 Node 环境都可以使用。

1.安装

npm install -g mocha

2.测试脚本

Mocha 的作用是运行测试脚本,首先必须学会写测试脚本。所谓”测试脚本”,就是用来测试源码的脚本。

add.js:

function add(x, y) {
  return x + y;
}
export default add;

要测试这个加法模块是否正确,就要写测试脚本。
通常,测试脚本与所要测试的源码脚本同名,但是后缀名为.test.js(表示测试)或者.spec.js(表示规格)。比如,add.js 的测试脚本名字就是 add.test.js

import { expect } from "chai";
import add from "../src/add.js";

describe("加法函数的测试:", function() {
  it("1 加 1 应该等于 2", function() {
    expect(add(1, 1)).to.be.equal(2);
  });
  it("1 加 1 应该不等于 3", function() {
    expect(add(1, 1)).to.not.be.equal(3);
  });
});

上面这段代码,就是测试脚本,它可以独立执行。测试脚本里面应该包括一个或多个 describe 块,每个 describe 块应该包括一个或多个 it 块。

describe 块称为”测试套件”(test suite),表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称(”加法函数的测试”),第二个参数是一个实际执行的函数。

it 块称为”测试用例”(test case),表示一个单独的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称(”1 加 1 应该等于 2”

Mocha 用法

mocha test/1_test.spec.js

Mocha 默认运行 test 子目录里面的测试脚本。所以,一般都会把测试脚本放在 test 目录里面,但是只执行目录第一层

chai.js

expect(add(1, 1)).to.be.equal(2);

所谓”断言”,就是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误。上面这句断言的意思是,调用 add(1, 1),结果应该等于 2。

所有的测试用例(it 块)都应该含有一句或多句的断言。它是编写测试用例的关键。断言功能由断言库来实现,Mocha 本身不带断言库,所以必须先引入断言库。

import { expect } from "chai";

断言库有很多种,Mocha 并不限制使用哪一种。上面代码引入的断言库是 chai,并且指定使用它的 expect 断言风格。

expect 断言的优点是很接近自然语言,下面是一些例子。详细

// 相等或不相等
expect(4 + 5).to.be.equal(9);
expect(4 + 5).to.be.not.equal(10);
expect(foo).to.be.deep.equal({ bar: "baz" });

// 布尔值为true
expect("everthing").to.be.ok;
expect(false).to.not.be.ok;

// typeof
expect("test").to.be.a("string");
expect({ foo: "bar" }).to.be.an("object");
expect(foo).to.be.an.instanceof(Foo);

// include
expect([1, 2, 3]).to.include(2);
expect("foobar").to.contain("foo");
expect({ foo: "bar", hello: "universe" }).to.include.keys("foo");

// empty
expect([]).to.be.empty;
expect("").to.be.empty;
expect({}).to.be.empty;

// match
expect("foobar").to.match(/^foo/);

基本上,expect 断言的写法都是一样的。头部是 expect 方法,尾部是断言方法,比如 equala/anokmatch 等。两者之间使用 toto.be 连接。

如果 expect 断言不成立,就会抛出一个错误。事实上,只要不抛出错误,测试用例就算通过。

it("1 加 1 应该等于 2", function() {});

上面的这个测试用例,内部没有任何代码,由于没有抛出了错误,所以还是会通过。

生命周期

Mocha 在 describe 块之中,提供测试用例的四个钩子:before()after()beforeEach()afterEach()。它们会在指定时间执行。

describe("hooks", function() {
  before(function() {
    // 在本区块的所有测试用例之前执行
  });

  after(function() {
    // 在本区块的所有测试用例之后执行
  });

  beforeEach(function() {
    // 在本区块的每个测试用例之前执行
  });

  afterEach(function() {
    // 在本区块的每个测试用例之后执行
  });

  // test cases
});

vue-test-utils

Vue Test Utils 是 Vue.js 官方的单元测试实用工具库。

<template>
  <div class="hello">
    <h1>{{ msgs }}</h1>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msgs: String
  }
}
</script>

上述代码是个 vue 组件传值的例子,通过 msgs 展示值的传递

import { expect } from "chai";
import { shallowMount } from "@vue/test-utils";
import HelloWorld from "@/components/HelloWorld.vue";

describe("HelloWorld.vue", () => {
  it("测试子组件传值", () => {
    const msgs = "new message";
    // 现在挂载组件,你便得到了这个包裹器
    const wrapper = shallowMount(HelloWorld, {
      propsData: {
        msgs
      }
    });
    expect(wrapper.text()).to.include(msgs);
  });
});

上述代码中看到shallowMount,这是一个官方提供的测试函数,它有 2 个参数。第一个参数是组件名,
第二个参数是个 Object

  • Count.vue
<template>
  <div>
    <input v-model="count" type="number" class="count">
    <button class="add" @click="add">+</button>
    <button class="minus" @click="minus">-</button>
    </div>
</template>
<script>
export default {
  data () {
    return {
      count: 0
    }
  },
  methods:{
      add(){
          this.count++
      },
      minus(){
          this.count--
      }
  }
}
</script>
import { expect } from "chai";
import { shallowMount } from "@vue/test-utils";
import Count from "@/components/Count.vue";

describe("Count.vue", () => {
  let wrapper;
  afterEach(() => {
    wrapper && wrapper.destroy();
  });
  it("点击按钮应该使得计数递增", () => {
    wrapper = shallowMount(Count);
    expect(wrapper.vm.count).to.equal(0);
    wrapper.find(".add").trigger("click");
    expect(wrapper.vm.count).to.equal(1);
  });
  it("点击按钮应该使得计数递减", () => {
    wrapper = shallowMount(Count);
    expect(wrapper.vm.count).to.equal(0);
    wrapper.find(".minus").trigger("click");
    expect(wrapper.vm.count).to.equal(-1);
  });
});

上述用例中提到了 vm,find,trigger,其中vm是 wrapper 的属性,可以访问一个实例所有的方法和属性。
find返回匹配选择器的第一个 DOM 节点或 Vue 组件的 Wrapper。trigger,在该 Wrapper DOM 节点上触发一个事件。

  • Input.vue
<template>
  <div>
    <input v-model="username">
    <div
      v-if="error"
      class="error"
    >
      {{ error }}
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      username: ''
    }
  },

  computed: {
    error () {
      return this.username.trim().length < 7
        ? '请输入大于6位的账号'
        : ''
    }
  }
}
</script>
describe("Input.vue", () => {
  it("测试Input组件校验长度", () => {
    // 渲染这个组件
    const wrapper = shallowMount(Input);
    // `username` 在除去头尾空格之后不应该少于 7 个字符
    wrapper.setData({
      username: " ".repeat(7)
    });
    // 确认错误信息被渲染了
    expect(wrapper.find(".error").exists()).to.be.true;

    // // 将名字更新至足够长
    wrapper.setData({
      username: "Lachlan"
    });
    // // 断言错误信息不再显示了
    expect(wrapper.find(".error").exists()).to.be.false;
  });
});

Wrapper

Wrapper 是一个包括了一个挂载组件或 vnode,以及测试该组件或 vnode 的方法。

包含以下属性:vm ,element ,options ;

以下方法:attributes([key]),classes([className]) ,contains(selector) ,destroy() ,emitted()….

参考资料

测试框架 Mocha 实例教程

Vue Test Utils

chai.js api 英文

chai.js api 中文

vue-cli 3.0

版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

评论