单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。简单来说,单元就是人为规定的最小的被测功能模块,可能是一个单一函数或方法、一个完整的组件或类。
单元测试是最小巧也是最简单的测试——它们通过隔离单个组件的每一个部分,来在最小工作单元上进行断言。
单元测试侧重:检验函数的输出结果
e2e (端到端) 测试,致力于确保组件的一系列交互是正确的。它们是更高级别的测试,例如可能会测试用户是否注册、登录以及更新他们的用户名。这种测试运行起来会比单元测试和快照比对测试慢一些。
e2e测试侧重:从用户视角,对真实系统的访问行为进行仿真
快照比对测试(snapshot testing)会保存你的 Vue 组件的标记,然后比较每次新生成的测试运行结果。如果有些东西改变了,开发者就会得到通知,并决定这个改变是刻意为之 (组件更新时) 还是意外发生的 (组件行为不正确)。
Jest、Mocha、Jasmine、sinon、chai、Karma、vue-test-utils都是什么?
名词 | 类型 | 名词 |
---|---|---|
Jest | 测试框架 | Jest由Facebook开发,用于测试JavaScript代码(尤其是使用React JS开发的应用程序 集成了断言、JSDom、覆盖率报告等,是一款几乎零配置的测试框架 提供snapshot功能 |
Mocha | 测试框架 | 基于JavaScript的自动化测试框架,用于测试使用Node.js运行的应用程序 比较年老的测试框架,在JavaScript界使用更广泛,可参考文献更多 |
Jasmine | 测试框架 | 主要用于异步测试,是一个功能丰富的JavaScript自动化测试框架 Jasmine需要很多配置 |
sinon | 测试框架 | 用于 JavaScript 的测试监视(spy)、桩(stub)和仿制(mock)功能。不依赖其他类库,兼容任何单元测试框架 |
chai | 断言库 | 一套TDD(测试驱动开发)/BDD(行为驱动开发)的断言库 expect/should库 |
Karma | 运行器 | 不是测试框架,也不是断言库,是允许你的JavaScript代码在复杂的浏览器运行的工具(抹平浏览器障碍) |
vue-test-utils | 单元测试工具库 | vue官方提供的,专门为测试单文件组件而开发 |
vue-test-utils是vue官方的单元测试框架,提供了一系列非常方便的工具,使我们更轻松地为vue构建的应用来编写单元测试。主流的JavaScript测试运行器有很多,但vue-test-utils都能支持。它是测试运行器无关的。
因为 jest 包含了 karma + mocha + chai + sinon 的所有常用功能,零配置开箱即用
Vue官方是这样描述的:
Jest 是功能最全的测试运行器。它所需的配置是最少的,默认安装了 JSDOM,内置断言且命令行的用户体验非常好。不过你需要一个能够将单文件组件导入到测试中的预处理器。我们已经创建了 vue-jest 预处理器来处理最常见的单文件组件特性,但仍不是 vue-loader 100% 的功能。
vue-test-utils在Vue和Jest之间提供了一个桥梁,暴露出一些接口,让我们更加方便地通过Jest为Vue应用编写单元测试
通过vue-cli创建模板脚手架时,可以选择是否启用单元测试,并且选择单元测试框架,这样Vue就帮助我们自动配置好了Jest
#1.运行命令,创建vue项目
vue create [project-name]
#2.选择"Manually select features" 和 "Unit Testing",以及 "Jest" 作为测试运行器。
#3. 安装完成,cd 进入项目目录中并运行
npm run test:unit
spec是specification(基准)的缩写,vue-test-uitls会默认找tests/unit下面的所有以spec后缀命名的js文件,跑文件里的测试脚本
import { shallowMount } from "@vue/test-utils"
import FormSubmitter from "@/components/FormSubmitter.vue"
describe("FormSubmitter", () => {
it("reveals a notification when submitted", async () => {
//安排
const wrapper = shallowMount(FormSubmitter)
//行动
wrapper.find("[data-username]").setValue("alice")
wrapper.find("form").trigger("submit.prevent")
await wrapper.vm.$nextTick()
//断言
expect(wrapper.find(".message").text())
.toBe("Thank you for your submission, alice.")
})
})
上面代码中的describe
块称为“测试套件”,表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称,第二个参数是实际执行的函数,分组让测试用例代码结构化,易于维护
it
块称为“测试用例”,表示一个单独的测试,是测试的最小单位
expect
是断言,它接受一个参数就是运行测试内容的结果,返回一个对象,这个对象来调用匹配器(toBe) ,匹配器的参数就是我们的预期结果,这样就可以对结果和预期进行对比了,也就可以判断对不对了,比如expect(1+1).toBe(2)
。
Vue 组件单元测试的一般思路:渲染这个组件,然后断言这些标签是否匹配组件的状态。
//SubmitButton.vue
<template>
<div>
<span v-if="isAdmin">Admin Privileges</span>
<span v-else>Not Authorized</span>
<button>{{ msg }}</button>
</div>
</template>
<script>
export default {
name: "SubmitButton",
props: {
msg: {
type: String,
required: true
},
isAdmin: {
type: Boolean,
default: false
}
}
}
</script>
<style scoped>
</style>
//SubmitButton.spec.js
import SubmitButton from "../../src/components/SubmitButton";
import {shallowMount} from "@vue/test-utils";
const msg = 'submit';
const factory = (propsData)=>{
return shallowMount(SubmitButton,{
//测试从父组件中接受属性(props)的组件
propsData:{
msg,
...propsData
}
})
}
describe('does not have admin privileges', () => {
it('renders a message', () => {
const wrapper = factory()
expect(wrapper.find("span").text()).toBe('Not Authorized')
expect(wrapper.find("button").text()).toBe('submit')
})
})
describe('has admin privileges', () => {
it('renders a message', () => {
const wrapper = factory({isAdmin: true})
expect(wrapper.find("span").text()).toBe('Admin Privileges')
expect(wrapper.find("button").text()).toBe('submit')
})
})
2019年最流行的五大JavaScript自动化测试框架
https://vue-test-utils.vuejs.org/zh/
vue测试指南
Jest单元测试入门