一篇文章学会 Nuxt 项目单元测试(实用版)

3,056 阅读2分钟

为什么选 jest

Jest是在Facebook开发的测试框架,可以让我的测试更加方便。jest自动集成了断言JSDom覆盖率报告等开发者所需要的所有测试工具,是一款几乎零配置的测试框架。

其实我的原因是因为

  • 它一套开源的 JavaScript 测试框架
  • 我并未用过其他的
  • 欢迎各位大佬仗义直言 🙂

安装Nuxt

npm run test 先跑起来看看

看到这个效果我们就算跑成功了

自己写一个例子

test目录下新建2个文件

  • sum.js
function sum(a, b) {
  return a + b;
}
module.exports = sum;

  • sum.test.js
const sum = require('./sum');

test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});

再次run起来

进入项目,打开文件jest.config.js

  • collectCoverage
    • 由于要带上覆盖率搜集语句重新访问所有执行过的文件,这可能会让你的测试执行速度被明显减慢
module.exports = {
  moduleNameMapper: { //类似 webpack.resolve.alias
    '^@/(.*)$': '<rootDir>/$1',
    '^~/(.*)$': '<rootDir>/$1',
    '^vue$': 'vue/dist/vue.common.js'
  },
  moduleFileExtensions: ['js', 'vue', 'json'], // 类似 webpack.resolve.extensions
  transform: { // 类似 webpack.module.rules
    '^.+\\.js$': 'babel-jest',
    '.*\\.(vue)$': 'vue-jest'
  },
  'collectCoverage': false, // 指出是否收集测试时的覆盖率信息
  'collectCoverageFrom': [ // 类似 webpack 的 rule.include
    '<rootDir>/components/**/*.vue',
    '<rootDir>/pages/**/*.vue'
  ]
}

再次run起来

对比区别很明显,我们collectCoverageFrom的文件没用检测,同样速度也会快些

Vscode 设置

安装 jest

在文件目录配置jest.config路径

可以实时看到Jest的输出结果了

用Jest编写第一个Vue.js组件单元测试

官方的VueJS测试库vue/test-utils

components目录下,新增几个文件

  • MessageList.vue
<template>
    <ul>
        <li v-for="message in messages">
            {{ message }}
        </li>
    </ul>
</template>

<script>
export default {
  name: 'list',
  props: ['messages']
}
</script>

修改Pages目录下的index.vue


<template>
  <div id="app">
    <MessageList :messages="messages" />
  </div>
</template>

<script>
import MessageList from "~/components/MessageList";
export default {
  name: "app",
  data: () => ({ messages: ["Hey John", "Howdy Paco"] }),
  components: {
    MessageList
  }
};
</script>

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

开始写我们的测试文件

test目录编写一个文件index.test.js

import Vue from "vue";
import pageIndex from '@/pages/index.vue'

describe("index.test.js", () => {
  let cmp, vm;

  beforeEach(() => {
    cmp = Vue.extend(pageIndex); // Create a copy of the original component
    vm = new cmp({
      data: {
        // Replace data value with this fake data
        messages: ["Cat"]
      }
    }).$mount(); // Instances and mounts the component
  });

  it('equals messages to ["Cat"]', () => {
    expect(vm.messages).toEqual(["Cat"]);
  });

产看输入结果/npm run test,测试应运行并通过 。

Snapshots功能

增加一个it

it("has the expected html structure", () => {
    expect(vm.$el).toMatchSnapshot();
 });

再次run 生成下面的一个文件

这里有一个大问题: 单元测试必须作为一个独立的单元进行测试,这意味着index.test.js我们要测试APP组件,而不应该影响其他的事情。想象一下,例如,子组件(MessageList在这种情况下)在created挂钩上执行了副作用操作,例如调用fetch,Vuex动作或状态更改?那不就不是我们想要的了嘛?

浅层渲染

浅层渲是一种确保组件在没有子对象的情况下进行渲染的技术

  • 仅测试要测试的组件(单元测试)
  • 避免子组件可能具有的副作用,例如进行HTTP调用,调用存储操作...

重写index.test.js

import { shallowMount } from "@vue/test-utils";
import pageIndex from '@/pages/index.vue'

describe("index.test.js", () => {
  let cmp;

  beforeEach(() => {
    cmp = shallowMount(pageIndex, {
      // Create a shallow instance of the component
      data: {
        messages: ["Cat"]
      }
    });
  });

  it('equals messages to ["Cat"]', () => {
    // Within cmp.vm, we can access all Vue instance methods
    expect(cmp.vm.messages).toEqual(["Cat"]);
  });

  it("has the expected html structure", () => {
    expect(cmp.element).toMatchSnapshot();
  });
});

选择重新生成快照(SnapShots),index被完全隔离,如果子组件中有任何钩子,则它们也不会被调用,比如created

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`App.test.js has the expected html structure 1`] = `
<div
  id="app"
>
  <!--  -->
</div>
`;

新增MessageList.test.js

import { mount } from "@vue/test-utils";
import MessageList from "~/components/MessageList";

describe("MessageList.test.js", () => {
  let cmp;

  beforeEach(() => {
    cmp = mount(MessageList, {
      // Be aware that props is overridden using `propsData`
      propsData: {
        messages: ["Cat"]
      }
    });
  });

  it('has received ["Cat"] as the message property', () => {
    expect(cmp.vm.messages).toEqual(["Cat"]);
  });

  it("has the expected html structure", () => {
    expect(cmp.element).toMatchSnapshot();
  });
});

npm run test