作者简介:

李中凯

八年多工作经验 前端负责人,

擅长JavaScript/Vue。

掘金文章专栏:KaysonLi 的个人主页 - 专栏 - 掘金


关于 Vue 组件单元测试最常见的问题就是“我究竟应该测试什么?”

虽然测试过多或过少都是可能的,但我的观察是,开发人员通常会测试过头。毕竟,没有人愿意自己的组件未经测试从而导致应用程序在生产中崩溃。

本文将分享一些用于组件单元测试的指导原则,这些指导原则可以确保在编写测试上不会花费大量时间,但是可以提供足够的覆盖率来避免错误。

本文假设你已经了解 Jest 和 Vue Test Utils。

示例组件

在学习这些指导原则之前,我们先来熟悉下要测试的示例组件。组件名为Item.vue ,是 eCommerce App 里的一个产品条目。

下面是组件的源码。注意有三个依赖项:Vuex ($store), Vue Router ($router) 和 Vue Auth ($auth)。

Item.vue

<template><div><h2>{{ item.title }}</h2><button @click="addToCart">Add To Cart</button><img :src="item.image"/></div>
</template>
<script>
export default {name: "Item",props: [ "id" ],computed: {item () {return this.$store.state.find(item => item.id === this.id);}},methods: {addToCart () {if (this.$auth.check()) {this.$store.commit("ADD_TO_CART", this.id);} else {this.$router.push({ name: "login" });}}}
};
</script>

配置 Spec 文件

下面是测试用的 spec 文件。其中,我们将用 Vue Test Utils “shallow mount”该示例组件,因此引入了相关模块以及我们要测试的 Item 组件。

同时还写了一个工厂函数用于生成可重
写的配置对象,以免在每个测试中都需要指定 props 和 mock 三个依赖项。item.spec.js

import { shallowMount } from "@vue/test-utils";
import Item from "@/components/Item";function createConfig (overrides) {const id = 1;const mocks = {// Vue Auth$auth: {check: () => false},// Vue Router$router: {push: () => {}},// Vuex$store: {state: [ { id } ],commit: () => {}}};const propsData = { id };return Object.assign({ mocks, propsData }, overrides);
}describe("Item.vue", () => {// Tests go here
});

确定业务逻辑

对于要测试的组件,要问的第一个也是最重要的问题是“业务逻辑是什么”,即组件是做什么的?

对于这个Item.vue,业务逻辑是:

  • 根据接收的id属性展示条目信息
  • 如果用户是访客,点击 Add to Cart 按钮将重定向到登录页
  • 如果用户已登录,点击 Add to Cart 按钮会触发 Vuex mutation ADD_TO_CART

确定输入和输出

当你对组件做单元测试时,可将其视为一个黑盒。方法、计算属性等内部逻辑只影响输出。

因此,下一个重点是确定组件的输入和输出,因为这些也是测试的输入和输出。

Item.vue 的输入是:

  • id 属性
  • 来自 Vuex 和 Vue Auth 的数据状态
  • 用户点击按钮

输出是:

  • 渲染后的 HTML
  • 发送到 Vuex mutation 或者 Vue Router push 的数据

有些组件也会将表单和事件作为输入,触发事件作为输出。

测试 1: 访客点击按钮后跳转路由

有一个业务逻辑是“如果用户是访客,点击 Add to Cart 按钮将重定向到登录页”。我们来写这个测试。

我们通过“shallow mount”该组件来编写测试,然后找到并点击Add to Cart 按钮。

test("router called when guest clicks button", () => {const config = createConfig();const wrapper = shallowMount(Item, config);wrapper.find("button").trigger("click");// Assertion goes here
}

随后我们会加上断言。

不要超出输入和输出的界限

在这个测试中很容易采取的做法是在点击按钮后判断路由是否跳转到了登录页,比如:

import router from "router";test("router called when guest clicks button", () => {...// 错!const route = router.find(route => route.name === "login");expect(wrapper.vm.$route.path).toBe(route.path);
}

虽然这确实也能测试组件的输出,但是它依赖于路由功能,这不应该是组件所关心的。

直接测试组件的输出会更好,也就是调用了 $router.push。至于路由是否最终完成了操作,这已经超出了本测试的范畴。

因此我们可以监听路由的 push 方法,并断言它是否被登录路由对象调用。

import router from "router";test("router called when guest clicks button", () => {...jest.spyOn(config.mocks.$router, "push");const route = router.find(route => route.name === "login");expect(spy).toHaveBeenCalledWith(route);
}

测试 2: 登录用户点击按钮后调用 vuex

接下来让我们测试业务逻辑“如果用户已登录,点击 Add to Cart 按钮将触发 Vuex mutation ADD_TO_CART”。

同样,你不需要判断 Vuex 状态是否更改了。要验证这个需要另外单独测试 Vuex store。

组件的职责只是执行 commit,因此我们只要测试这个动作就行。

首先重写 $auth.check 假数据让它返回 true (模拟登录用户)。然后监听 store 的 commit 方法,并断言点击按钮后被调用。

test("vuex called when auth user clicks button", () => {const config = createConfig({mocks: {$auth: {check: () => true}}});const spy = jest.spyOn(config.mocks.$store, "commit");const wrapper = shallowMount(Item, config);wrapper.find("button").trigger("click");expect(spy).toHaveBeenCalled();
}

不要测试其他库的功能

Item 组件展示条目数据,特别是标题和图片。或许我们应该写一个测试来专门检查这些?比如:

test("renders correctly", () => {const wrapper = shallowMount(Item, createConfig());// Wrongexpect(wrapper.find("h2").text()).toBe(item.title);
}

这又是一个不必要的测试,因为它只是测试了 Vue 从 Vuex 中提取数据并插入到模板的能力。Vue 这个库已经对该机制进行了测试,所以你应该直接依赖于它。

测试 3: 正确地渲染

但是等等,如果有人不小心将title重命名为name,然后忘记更新插值表达式怎么办?这难道不需要测试吗?

没错,但是如果你像这样来测试模板的方方面面,什么时候才是个头?

测试 HTML 最好的办法是使用快照,用来检查整体渲染后的结果。这不仅覆盖了标题插值,还包括图片、按钮文本、任何 class 等。

test("renders correctly", () => {const wrapper = shallowMount(Item, createConfig());expect(wrapper).toMatchSnapshot();
});

其他不需要测试的点还有这些:

  • src 属性是否绑定到 img 元素
  • 添加到 Vuex store 中的数据是否跟插入的数据一致
  • 计算属性是否返回了正确的数据
  • 执行 router push 是否重定向到正确的页面

诸如此类。

总结

我认为上面三个简单的测试对这个组件来说足够了。组件单元测试的一个好理念是先假设测试是不必要的,除非被证明是必要的。你可以问自己以下问题:

  • 这是业务逻辑的一部分吗?
  • 这是直接测试组件的输入和输出吗?
  • 这是测试自己的代码,还是第三方代码?

作者简介:

李中凯

八年多工作经验 前端负责人,

擅长JavaScript/Vue。

掘金文章专栏:KaysonLi 的个人主页 - 专栏 - 掘金

本文已经获得李中凯老师授权转发,其他人若有兴趣转载,请直接联系作者授权。

更多的学习资料,请看这里:

http://www.jnshu.com/login/1/36856070?source=zhihu-article-lizhongkai

vue路由重定向到登录页面_Vue 组件单元测试究竟测试什么?相关推荐

  1. testid oracle vue,Vue 组件单元测试究竟测试什么?

    关于 Vue 组件单元测试最常见的问题就是"我究竟应该测试什么?" 虽然测试过多或过少都是可能的,但我的观察是,开发人员通常会测试过头.毕竟,没有人愿意自己的组件未经测试从而导致应 ...

  2. Vue 组件单元测试究竟测试什么?

    作者简介: 李中凯 八年多工作经验 前端负责人, 擅长JavaScript/Vue. 掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/po ...

  3. vue 路由重定向_使用Vue和Vue路由器进行高级路由:重定向和Nav Guard

    vue 路由重定向 While the basics of routing in Vue.js have already been covered, today we'll explore some ...

  4. vue路由重定向和动态路由

    vue路由重定向和动态路由 文章目录 vue路由重定向和动态路由 vue路由重定向 动态路由 vue路由重定向 实现页面跳转一般有两种方式:重定向页面和转发页面. 重定向页面的具体实现方式就是更改页面 ...

  5. java403forbidden_java – Spring boot – 返回403 Forbidden而不是重定向到登录页面

    在Spring Boot Web应用程序中,我有以下安全配置: @Override public void configure(HttpSecurity http) throws Exception ...

  6. vue拦截器刷新登陆页面_Vue + Spring Boot 项目实战(六):前端路由与登录拦截器-Go语言中文社区...

    前言 这一篇主要讲前端路由与登录拦截器的实现.放在一起讲是因为我在开发登录拦截器时因为这个路由的问题遇到了很多坑,花费了很长时间,网上的解决方案都不怎么靠谱,综合了好几种办法才最终成功,其实关于这个部 ...

  7. vue拦截器刷新登陆页面_vue 一刷新就退回登录页面了

    写项目时,遇到一个问题就是,我配置好拦截器和路由拦截,没有报错,感觉可以,但是会到页面登录成功后,操作数据后,习惯性点击刷新,这时就退回到登录页面了,我知道是我清空存储的值,但是现在觉得用户万一刷新就 ...

  8. 框架技术Vue --- 路由、后台管理系统页面

    Vue框架 内容管理 前端路由 前端路由的工作方式 实现简易的前端路由 created中window.onhashchange vue-router基本使用 router-link的hash地址不需要 ...

  9. linux下服务器重定向,linux – DHCP服务器将任何URL重定向到登录页面

    我有一个Linux DHCP服务器,我需要将所有网络流量重定向到一个登陆页面,该登陆页面将提供有关如何在网络上注册计算机的说明. 无论用户输入什么URL,都需要将用户重定向到网页(在DHCP服务器上) ...

最新文章

  1. c++中的对象引用(object reference)与对象指针的区别
  2. 更换VC后DDC提示证书不可用
  3. 简单介绍Lua中三种循环语句的使用
  4. C#编程总结--总目录
  5. win10更新后程序路径盘符变成*星号解决方法
  6. Python为何能成为数据分析的主流工具?
  7. (整理)C/C++野指针
  8. 开源视频平台:MediaCore(MediaDrop)
  9. Mongoose使用——nodejs结合mongodb
  10. babel 配置整理
  11. [UPF]理解UPF功率域和域边界
  12. ar ebs 销售订单关闭_雅视推AR眼镜虚拟试戴,眼镜行业科技转型强信号
  13. windows 10 账号密码策略及规则
  14. bat 脚本操作注册表
  15. python header函数_Header函数
  16. php源码dede,php网站管理系统 DedeCMS v5.7 SP2 UTF8 20180109正式版
  17. “金三银四” 是找工作的最佳时期吗?
  18. 《微信小程序-证件照换底色》之三:微信小程序接收django的图片并部署到windows服务器上
  19. 当我们谈战略,我们究竟在谈什么?
  20. Hive 热门数据分析笔试题(干货满满,持续更新中...)

热门文章

  1. 《Robust High-Resolution Video Matting with Temporal Guidance》论文笔记
  2. 三分钟教会你Linux网卡安装
  3. Android7.0华为Mate9开发获取WiFi列表失败
  4. 稻盛和夫:打造两个世界500强的强者思维
  5. 解析超市生鲜供应链升级与数字化运营转型价值,聚力核心竞争力打造
  6. 模板引擎——Jade学习笔记
  7. 目录扫描工具 dirbuster
  8. 用按键精灵理解线程和进程
  9. 检索算法: BM25原理详解
  10. 苹果审核上传附件上传不上去