vue 单元测试初探

目录
  • 前言
  • 为什么要引进单元测试?
  • 单元测试概述
  • 测试开发的模式
    • 1. 测试驱动开发(TDD - Test Driven Development)
    • 2. 行为驱动开发(BDD - Behavior Driven Development)
  • Vue中的单元测试
  • 框架选择
  • Vue Test Utils
  • 文档

前言

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单,在vue、react、angular等前端框架中,最重要的是针对组件的单元测试

为什么要引进单元测试?

现今时代,各种编程语言,开发框架,集成工具蓬勃发展,然而软件工程师们却仍然挣扎在第一线,被bug、遗留代码、技术债务、重构搞得焦头烂额,当你的项目足够大的时候,在叠加模块和组件的过程中,是很有可能影响之前的模块。但是被影响的模块已经通过了测试,我们在迭代的时候,很少有测试人员会去重新测试这个系统。所以, 被影响的模块很可能就有了一个隐形的bug被部署到线上。因此我们采用自动化测试。最主要的作用是对于大型项目,在每次迭代的时候, 可以保证整个系统的正确运行, 确保系统的健壮,总结以下几点:

  • 自动化的测试,节省时间
  • 减少低级的bug
  • 提供了对组件行为描述的文档
  • 能在编写单测中改进代码
  • 利于阅读组件,促进重构
  • 证明你的工作已完成
  • 利于代码评审
  • 代码性能
  • 提供一些度量指标

单元测试概述

单元测试通常是针对应用程序中最小的部分,在vue中组件是要测试的单元(后面介绍)

首先,我们来开始一个简单的单元测试,在代码中,使用sum函数计算两数之和。

单元测试是在源代码中单独调用函数并断言其行为正确的函数,看看如下的例子,这是一个比较简单的程序,导出一个sum函数,然后运行该函数,断言其如果不返回则抛出错误。

// sum.js
export default function sum(a,b){
    return a + b
}
// sum.spec.js
import sum from './sum.js'
function testSum(){
    if(sum(1,2)!==3){
        throw new Error('sum(1,2) not return 3')
    }
}
testSum()

因为单元测试是针对隔离的单元进行测试的,所以当编写出良好的单元测试,能准确的将代码问题暴露出来。

另外在测试中,我们可能会关注快照测试,快照测试类似于差异发现,快照测试将运行的程序进行截图比较,如果存在差异,则会显示错误,在vue测试中,vueTestUtil提供了类似的能力,可以比较js中可序列化的值,在组件中就是比较dom输出

测试开发的模式

如果你关注测试开发方面的知识,你应该听说过测试驱动开发(TDD - Test Driven Development)以及行为驱动开发(BDD - Behavior Driven Development)

1. 测试驱动开发(TDD - Test Driven Development)

测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法。它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代码,并加速开发过程

首先,开发人员在编写业务逻辑之前,先编写一些测试用例 如果运行这些测试用例,会得到失败的结果,因为我们根本没有实现要测试的业务逻辑 实现这些业务逻辑 运行测试用例,查看通过率,如果你是一个优秀的开发者,可能这些用例都可以通过 修复测试用例,或者重构

当我们开发新功能时,依然是重复上述步骤,核心就是测试用例前置,流程图如下:

举个栗子: 我们通过具体的实例来描述一下TDD,假设我们现在的需求是实现一个阶乘函数,我们使用jest来实现这个测试用例

var fac = require("../src/index.js");

test("输入负数,应该返回NaN ", () => {
  expect(fac(-1)).toBe(NaN);
});

test("输入0,应该返回1 ", () => {
  expect(fac(0)).toBe(1);
});

test("输入1,应该返回1 ", () => {
  expect(fac(1)).toBe(1);
});

test("输入2,应该返回2", () => {
  expect(fac(2)).toBe(2);
});

test("输入3,应该返回6", () => {
  expect(fac(3)).toBe(6);
});

运行这个测试用例,肯定会失败,因为我们还没有实现这个fac函数,接下来我们来实现这个阶乘函数

module.exports = function fac(n) {
  if (n < 0) return NaN;
  if (n === 0) return 1;
  return n * fac(n - 1);
};

现在我们再次运行这个测试用例,得到如下结果:

可以看到,所有的case都通过了,这个就是TDD的开发模式

2. 行为驱动开发(BDD - Behavior Driven Development)

在传统软件开发中,业务人员拿到需求,将需求交给需求分析人员,需求分析人员编写需求说明书或者设计,然后软件开发人员根据需求说明进行架构设计和代码开发,接着测试人员根据需求说明编写测试用例进行测试,从需求产生到测试交付,有多个不同角色的参与,期间很容易产生信息丢失与理解偏差,其中只要出现一个环节错误,研发团队就很难交付合格的产品。

BDD是一种敏捷软件开发的技术,它鼓励软件中的开发者、QA和非技术人员或商业参与者之间的协作,特别适用于敏捷项目

举个栗子描述一下:

var fac = require("../src/index.js");

describe("验证阶乘函数 fac:", function () {
  it("输入负数,应该返回NaN ", () => {
    expect(fac(-1)).toBe(NaN);
  });

  it("输入0,应该返回1 ", () => {
    expect(fac(0)).toBe(1);
  });

  it("输入1,应该返回1 ", () => {
    expect(fac(1)).toBe(1);
  });

  it("输入2,应该返回2", () => {
    expect(fac(2)).toBe(2);
  });

  it("输入3,应该返回6", () => {
    expect(fac(3)).toBe(6);
  });
});

运行测试用例,得到结果:

对比代码内容与测试结果,发现差别并不大,最主要的区别就是措辞的区别,BDD的测试用例看起来就像是在看一篇文档一样,结构十分清晰,对于团队配合,代码阅读,促进重构有着不可小觑的作用,当你可以流畅的阅读测试用例的时候,自然也能编写出更好的代码。

这里的例子只是描述与测试驱动开发的差别,并不能代表真正的行为驱动开发,行为驱动开发更像是一种概念理论

总结:BDD更加注重功能的而不只是关注结果,另外借用一句业内名言:BDD帮助开发人员设计(design)软件,TDD帮助开发人员测试(test)软件。

Vue中的单元测试

单元测试允许你将独立单元的代码进行隔离测试,其目的是为开发者提供对代码的信 心。通过编写细致且有意义的测试,你能够有信心在构建新特性或重构已有代码的同时,保持应用的功能和稳定。 为一个 Vue 应用做单元测试并没有和为其它类型的应用做测试有什么明显的区别。

框架选择

如果你是Vue的开发者,你应该十分了解vue的组件中template的写法,template、style、script模板式的语法,相对于React中Jsx语法更加直接和自然,Vue中将组件作为最小测试单元十分合适。

虽说单元测试通常与框架并没有直接关系,但是对于功能集合、性能和对单文件组件预编译的支持、单测产生价值以及开发过程的便捷性你需要对其进行评估。

一流的错误报告

当测试失败时,提供有用的错误信息对于单元测试框架来说至关重要。这是断言库应尽的职责。一个具有高质量错误信息的断言能够最小化调试问题所需的时间。除了简单地告诉你什么测试失败了,断言库还应额外提供上下文以及测试失败的原因,例如预期结果 vs. 实际得到的结果。 一些诸如 Jest 这样的单元测试框架会包含断言库。另一些诸如 Mocha 需要你单独安装断言库 (通常会用 Chai)。

活跃的社区和团队

因为主流的单元测试框架都是开源的,所以对于一些旨在长期维护其测试且确保项目本身保持活跃的团队来说,拥有一个活跃的社区是至关重要的。额外的好处是,在任何时候遇到问题时,一个活跃的社区会为你提供更多的支持。

这里我们综合考虑使用Jest框架,Jest 是一个专注于简易性的 JavaScript 测试框架。一个其独特的功能是可以为测试生成快照 (snapshot),以提供另一种验证应用单元的方法。

Jest 是功能最全的测试运行器。它所需的配置是最少的,默认安装了 JSDOM,内置断言且命令行的用户体验非常好。

Jest资料

Jest 官网

Vue CLI 官方插件 - Jest

Vue官方提供了十分便捷的测试工具库:Vue Test Utils,接下来会讲解如何使用 Vue Test Utils 对vue的组件进行单元测试。

Vue Test Utils

它提供了丰富的API,拥有渲染组件实例,选择器、模拟插入全局组件、模拟状态、数据流、生命周期、事件等强大的功能,甚至可以模拟路由等,接下来我们来尝试一下。

安装:

安装Vue Test Utils的方式并不难,我们先选择一个测试运行器,可以选择 Jest或者Mocha,这里我们选择Jest。

如果您还没有使用Vue-cli创建项目,可以在vue-cli创建项目时选择Jest,框架会自动安装Vue Test Utils,运行:

 vue create vue-test

如果您已经有通过Vue-cli创建的项目,则可以运行:

    vue add @vue/unit-jest

配置Jest: jest的配置可以放到根目录的jest.config.js 或者 jest.config.json里面

module.exports = {
  preset: "@vue/cli-plugin-unit-jest", // 单测插件
  moduleFileExtensions: ["js", "json", "vue", "less", "css"], // 后缀
  transform: { // 模块解析
    "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
    ".*\\.(vue)$": "<rootDir>/node_modules/vue-jest",
  },
  moduleNameMapper: { // 别名识别
    "^@/(.*)$": "<rootDir>/src/$1",
    "\\.(css|less)$": "<rootDir>/tests/mocks/styleMock.js",
  },
  // 快照解析 需要安装 jest-serializer-vue
  snapshotSerializers: ["<rootDir>/node_modules/jest-serializer-vue"],
  collectCoverage: true,
  // 覆盖率目录
  coverageDirectory: "report/coverage",
  // 单测报告配置,需要安装jest-html-reporter
  reporters: [
    "default",
    [
      "./node_modules/jest-html-reporter",
      {
        logo: "https://rdc-test.mingyuanyun.com/static/img/rdc.png",
        pageTitle: "单测报告(工作台)",
        outputPath: "report/unit-test/index.html",
        includeFailureMsg: true,
      },
    ],
  ],
};

需要安装的模块:

  • jest-serializer-vue(序列化工具)
  • jest-html-reporter(单测报告工具,也可以选择其他工具)

配置完成后,我们就可以愉快地运行单测啦

如下所示,这是一个十分简单的点击数字自增的组件:

// Increment.js
<template>
  <div>
    <p>number is {{ count }}</p>
    <button @click="increment">increment</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    increment() {
      this.count++;
    },
  },
};
</script>

<style scoped lang="less">
p {
  font-size: 2em;
  text-align: center;
}
</style>

Vue Test Utils提供了实现包裹器的方法,mount,shallowMount,获取包裹器后,我们可以开始使用其实例上封装的众多接口

// increment.spec.js
// 导入测试工具集
import { mount } from "@vue/test-utils";
import Increment from "@/views/Increment";

describe("Increment", () => {
  // 挂载组件,获取包裹器
  const wrapper = mount(Increment);
  const vm = wrapper.vm;
  it("render markup", () => {
    expect(wrapper.html()).toContain("<p>number is 0</p>");
  });

  // 模拟用户点击
  it("button click should increment the count", () => {
    expect(vm.count).toBe(0);
    const button = wrapper.find("button");
    button.trigger("click");
    expect(vm.count).toBe(1);
  });

  // 点击后查看dom
  it("button click should increment the count and update the dom", async () => {
    expect(wrapper.text()).toContain("1");
    const button = wrapper.find("button");
    await button.trigger("click");
    expect(wrapper.text()).toContain("2");
  });
});

写好单元测试后,我们来执行一下:

npm run test:unit

运行完成后,在我们项目根目录,可以查看到单测报告 report/unit-test/index.html ,在浏览器打开,就可以查看

打开coverage/lcov-report/index.html可以查看覆盖率

好了,我们现在已经完成一个简单的单元测试用例了,我们使用了挂载、包裹器、选择器,事件触发器等,具体还有很多的API可以查看官方文档

文档

Vue Test Utils官方文档

以上就是vue 单元测试初探的详细内容,更多关于vue 单元测试的资料请关注我们其它相关文章!

(0)

相关推荐

  • 如何为vue的项目添加单元测试

    动机 单元测试能避免出现一些代码运行结果与预期不符的错误,通常是一些比较低级但又难以发现的问题. 粗心且懒,在每次调整之后,需要不断地检查代码,反复去走流程.担心由于自己的改动而导致了逻辑上的错误.而这里面的一大部分工作其实可以让单元测试来完成. 有了单元测试之后,可以对代码本身形成一种规范.如果在进行单元测试过程中发现自己的一些代码不方便进行测试,那么你可能需要重新审视这些代码,看是否有一些设计上不合理或者可以优化的地方. 嵌入了单元测试的项目显得更加的专业,也会更有逼格,测试本身是开发环节需

  • 使用Karma做vue组件单元测试的实现

    养成良好的编码习惯,一个合格的程序员需要掌握一些编写单元测试的能力.单元测试也可以整体上提升我们的代码质量,这里介绍下 VUE 组件的单元测试. 如果想直接通过 Demo 学习,可以跳过下面的内容,点击这里下载示例 技术栈 @vue/test-utils[1.0.0-beta.30] istanbul-instrumenter-loader[3.0.1] karma[4.4.1] karma-chrome-launcher[3.1.0] karma-mocha[1.3.0] karma-sour

  • vue项目中添加单元测试的方法

    从网上找了很多例子关于单元测试,都是如何新建项目的时候的添加单元测试,用vue-cli中怎么添加,但是我的项目已经生成了,不能再一次重新初始化,这时如何添加单元测试,这里面遇到了好多坑,写在这里记录一下心得. 1.用vue-cli生成一个新的项目,把单元测试需要的文件直接复制到你的项目中 vue init webpack vuetest 2.安装Karma+Mocha模块,这个模块依赖比较多,我在遇到了坑,解决问题半天发现缺少了某个模块,在这里全部列出需要的模块 复制代码 代码如下: npm i

  • 详解关于Vue单元测试的几个坑

    一.写在前面 这篇文章的代码使用karma,mocha,chai,sinon-chai配合Vue的实例属性进行单元测试 二.全局的组件的坑 由于我的g-icon是全局注册的,所以使用g-input组件时的时候g-icon是直接用的,所以测试时有关icon的代码永远是错的. 把g-icon局部注册的组件 三.在测试中触发点击事件 模拟我在app.vue里使用g-input组件 <g-input v-model="message"></g-input> 使用new

  • 详解使用jest对vue项目进行单元测试

    最近领导对前端提出了新的要求,要进行单元测试.之前使用vue做了一个快报名小程序的pc端页面,既然要做单元测试,就准备用这个项目了,之前有些react的经验,vue还是第一遭 vue-cli3.0单元测试方面更加完备,就先升级到了cli3.0,因为项目是用typescript写的,需要ts-jest,得到jest的配置如下 { "jest": { "moduleFileExtensions": [ "js", "jsx", &

  • 对 Vue-Router 进行单元测试的方法

    由于路由通常会把多个组件牵扯到一起操作,所以一般对其的测试都在 端到端/集成 阶段进行,处于测试金字塔的上层.不过,做一些路由的单元测试还是大有益处的. 对于与路由交互的组件,有两种测试方式: 使用一个真正的 router 实例 mock 掉 $route  和 $router  全局对象 因为大多数 Vue 应用用的都是官方的 Vue Router,所以本文会谈谈这个. 创建组件 我们会弄一个简单的 <App>,包含一个  /nested-child  路由.访问 /nested-child

  • vue 单元测试的推荐插件和使用示例

    目录 框架 一流的错误报告 活跃的社区和团队 Jest Mocha 推荐插件 Vue Testing Library (@testing-library/vue) Vue Test Utils 示例 单元测试应该: 可以快速运行 易于理解 只测试一个独立单元的工作 框架 因为单元测试的建议通常是框架无关的,所以下面只是当你在评估应用的单元测试工具时需要的一些基本指引. 一流的错误报告 当测试失败时,提供有用的错误信息对于单元测试框架来说至关重要.这是断言库应尽的职责.一个具有高质量错误信息的断言

  • 浅谈Vue组件单元测试究竟测试什么

    关于 Vue 组件单元测试最常见的问题就是"我究竟应该测试什么?" 虽然测试过多或过少都是可能的,但我的观察是,开发人员通常会测试过头.毕竟,没有人愿意自己的组件未经测试从而导致应用程序在生产中崩溃. 在本文中,我将分享一些用于组件单元测试的指导原则,这些指导原则可以确保在编写测试上不会花费大量时间,但是可以提供足够的覆盖率来避免错误. 本文假设你已经了解 Jest 和 Vue Test Utils. 示例组件 在学习这些指导原则之前,我们先来熟悉下要测试的示例组件.组件名为 Item

  • vue-cli3 karma单元测试的实现

    Karma Karma是一个测试工具,能让你的代码在浏览器环境下测试.代码可能是设计在浏览器端执行的,在node环境下测试可能有些bug暴露不出来(比如要做样式的测试),如果你的代码只会运行在node端,那么你不需要用karma. vue-cli3 结合karma 经过查找搜索到vue-cli-plugin-unit-karma插件, 集成vue-cli3与karma,但是结果不那么完美,执行的时候还是报错. 不过功夫不负有心人,终于找到解决方法,步骤如下 安装依赖 npm install --

  • 详解Vue单元测试case写法

    书接上文,karma+webpack搭建vue单元测试环境介绍了vue单元测试环境搭建及查看源文件的测试覆盖覆盖率.今天来说一下vue单元测试思路和case的写法.测试框架使用jasmine,语法参考. 代码地址:https://github.com/MarxJiao/vue-karma-test/tree/spec-demo 测试关注点 对于vue组件,单元测试测试主要关注以下几点: vue组件加载后,各数据模型是否符合预期 定义的方法是否可用 filter是否可用 带有props的组件,数据

  • 教你如何编写Vue.js的单元测试的方法

    Vue.js是一个JavaScript框架,可用于构建Web应用程序的前端框架.特别是在创建复杂功能时,对于每个项目,有必要在我们的应用程序中查看所有内容,并检查它是否符合预期.然而,对于大型项目,每次新的更新后,检查每个功能将变得很麻烦.因此,我们可以创建可以一直运行的自动化测试,并保证我们的代码可以正常运行.在本文中,我们将为VueJS创建一些简单的单元测试. 要进行测试,我们将先制作一个基本的待办事项列表组件.我们将测试该列表是否正确显示,并且用户可以将新项目添加到待办事项列表中.希望在本

随机推荐