Vue 组件的单元测试

2023-11-12

1、基本的示例

单元测试是软件开发非常基础的一部分。单元测试会封闭执行最小化单元的代码,使得添加新功能和追踪问题更容易。Vue 的单文件组件使得为组件撰写隔离的单元测试这件事更加直接。它会让你更有信心地开发新特性而不破坏现有的实现,并帮助其他开发者理解你的组件的作用。
这是一个判断一些文本是否被渲染的简单的示例:

<template>
  <div>
    <input v-model="username">
    <div
      v-if="error"
      class="error"
    >
      {{ error }}
    </div>
  </div>
</template>
<script>
export default {
  name: 'Hello',
  data () {
    return {
      username: ''
    }
  },
  computed: {
    error () {
      return this.username.trim().length < 7
        ? 'Please enter a longer username'
        : ''
    }
  }
}
</script>
import { shallowMount } from '@vue/test-utils'
import Hello from './Hello.vue'
test('Hello', () => {
  // 渲染这个组件
  const wrapper = shallowMount(Hello)
  // `username` 在除去头尾空格之后不应该少于 7 个字符
  wrapper.setData({ username: ' '.repeat(7) })
  // 确认错误信息被渲染了
  expect(wrapper.find('.error').exists()).toBe(true)
  // 将名字更新至足够长
  wrapper.setData({ username: 'Lachlan' })
  // 断言错误信息不再显示了
  expect(wrapper.find('.error').exists()).toBe(false)
})

上述代码片段展示了如何基于 username 的长度测试一个错误信息是否被渲染。它展示了 Vue 组件单元测试的一般思路:渲染这个组件,然后断言这些标签是否匹配组件的状态。

2、为什么要测试?

组件的单元测试有很多好处:

  • 提供描述组件行为的文档
  • 节省手动测试的时间
  • 减少研发新特性时产生的 bug
  • 改进设计
  • 促进重构自动化测试使得大团队中的开发者可以维护复杂的基础代码

3、实际的例子

单元测试应该:

  • 可以快速运行
  • 易于理解
  • 只测试一个独立单元的工作我们在上一个示例的基础上继续构建,同时引入一个工厂函数 (factory function)使得我们的测试更简洁更易读。这个组件应该:
  • 展示一个“Welcome to the Vue.js cookbook”的问候语
  • 提示用户输入用户名
  • 如果输入的用户名少于七个字符则展示错误信息让我们先看一下组件代码:
<template>
  <div>
    <div class="message">
      {{ message }}
    </div>
    Enter your username: <input v-model="username">
    <div
      v-if="error"
      class="error"
    >
      Please enter a username with at least seven letters.
    </div>
  </div>
</template>
<script>
export default {
  name: 'Foo',
  data () {
    return {
      message: 'Welcome to the Vue.js cookbook',
      username: ''
    }
  },
  computed: {
    error () {
      return this.username.trim().length < 7
    }
  }
}
</script>

我们应该测试的内容有:

  • message 是否被渲染
  • 如果 error 是 true,则
    应该展示
  • 如果 error 是 false,则
    不应该展示我们的第一次测试尝试:
import { shallowMount } from '@vue/test-utils'
import Foo from './Foo.vue'
describe('Foo', () => {
  it('renders a message and responds correctly to user input', () => {
    const wrapper = shallowMount(Foo, {
      data: {
        message: 'Hello World',
        username: ''
      }
    })
    // 确认是否渲染了 `message`
    expect(wrapper.find('.message').text()).toEqual('Hello World')
    // 断言渲染了错误信息
    expect(wrapper.find('.error').exists()).toBeTruthy()
    // 更新 `username` 并断言错误信息不再被渲染
    wrapper.setData({ username: 'Lachlan' })
    expect(wrapper.find('.error').exists()).toBeFalsy()
  })
})

上述代码有一些问题:

  • 单个测试断言了不同的事情
  • 很难阐述组件可以处于哪些不同的状态,以及它该被渲染成什么样子接下来的示例从这几个方面改善了测试:
  • 每个 it 块只做一个断言
  • 让测试描述更简短清晰
  • 只提供测试需要的最小化数据
  • 把重复的逻辑重构到了一个工厂函数中 (创建 wrapper 和设置 username 变量)更新后的测试:
import { shallowMount } from '@vue/test-utils'
import Foo from './Foo'
const factory = (values = {}) => {
  return shallowMount(Foo, {
    data () {
      return {
        ...values
      }
    }
  })
}
describe('Foo', () => {
  it('renders a welcome message', () => {
    const wrapper = factory()
    expect(wrapper.find('.message').text()).toEqual("Welcome to the Vue.js cookbook")
  })
  it('renders an error when username is less than 7 characters', () => {
    const wrapper = factory({ username: ''  })
    expect(wrapper.find('.error').exists()).toBeTruthy()
  })
  it('renders an error when username is whitespace', () => {
    const wrapper = factory({ username: ' '.repeat(7)  })
    expect(wrapper.find('.error').exists()).toBeTruthy()
  })
  it('does not render an error when username is 7 characters or more', () => {
    const wrapper = factory({ username: 'Lachlan'  })
    expect(wrapper.find('.error').exists()).toBeFalsy()
  })
})

注意事项:
在一开始,工厂函数将 values 对象合并到了 data 并返回了一个新的 wrapper 实例。这样,我们就不需要在每个测试中重复 const wrapper = shallowMount(Foo)。另一个好处是当你想为更复杂的组件在每个测试中伪造或存根一个方法或计算属性时,你只需要声明一次即可。

4、额外的上下文

上述的测试是非常简单的,但是在实际情况下 Vue 组件常常具有其它你想要测试的行为,诸如:

  • 调用 API
  • 为 Vuex 的 store,commit 或 dispatch 一些 mutation 或 action
  • 测试用户交互我们在 Vue Test Utils 的教程中提供了更完整的示例展示这些测试。
    Vue Test Utils 及庞大的 JavaScript 生态系统提供了大量的工具促进 100% 的测试覆盖率。单元测试只是整个测试金字塔中的一部分。其它类型的测试还包括 e2e (端到端) 测试、快照比对测试等。单元测试是最小巧也是最简单的测试——它们通过隔离单个组件的每一个部分,来在最小工作单元上进行断言。

快照比对测试会保存你的 Vue 组件的标记,然后比较每次新生成的测试运行结果。如果有些东西改变了,开发者就会得到通知,并决定这个改变是刻意为之 (组件更新时) 还是意外发生的 (组件行为不正确)。

端到端测试致力于确保组件的一系列交互是正确的。它们是更高级别的测试,例如可能会测试用户是否注册、登录以及更新他们的用户名。这种测试运行起来会比单元测试和快照比对测试慢一些。

单元测试中开发的时候是最有用的,即能帮助开发者思考如何设计一个组件或重构一个现有组件。通常每次代码发生变化的时候它们都会被运行。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Vue 组件的单元测试 的相关文章

  • 将 VueJs 组件添加到 Django 模板中

    我正在开发一个 Django 网站 我希望将一些 Vue 组件 散布 到 Django 渲染的模板中 我正在单个存储库中工作 并使用 webpack 设置来创建我在 Django 模板中使用的 style js 包 我正在努力让功能按照我想
  • 如何隔离 Vuetify 全局样式

    我已经开始在旧的现有项目中将 Vue js 与 Vuetify 结合使用 所以我没有重写所有前端 我只是导入了Vue并替换了一些部分 然后我注意到一个非常意想不到的行为 Vuetify 具有常见类的全局样式 例如 title它不仅影响整个页
  • 模拟安装挂钩 Jest 测试装置

    我正在对组件进行一些单元测试 但是 在某些组件中 我有一些东西在运行mounted使我的测试失败的钩子 我设法模拟了我不需要的方法 但是 我想知道是否有一种解决方法可以模拟mounted钩住自己 components attendeesLi
  • Web 扩展中共享 vuex 状态(死对象问题)

    我正在尝试在网络扩展中使用共享的 vue js 状态 状态存储在后台脚本的 DOM 中并呈现在弹出页面中 第一次尝试 我的第一次尝试是使用一个没有 vuex 的简单商店 背景 js var store count 0 popup js br
  • Asyncdata 与 Fetch 之间的区别

    获取数据和异步数据之间的确切区别是什么 官方文档是这么说的 异步数据 您可能想要获取数据并在服务器端呈现它 Nuxt js 添加 asyncData 方法 让您可以在之前处理异步操作 设置元件数据 异步数据每次在加载组件之前调用 仅适用于
  • 如何修复套接字 io 中的 400 错误错误请求?

    我有一个前端应用程序 VUE JS 我有一个后端 Nest JS Vue JS 应用程序使用 vue socket io extended 库通过 websockets 从后端获取数据 当 Vue JS 应用程序启动时 我在浏览器中看到错误
  • 过滤掉来自第三方框架的log4j消息?

    如何过滤来自外部第三方框架的日志消息 我正在使用 Hibernate 和 Spring 框架 我想抑制日志 以便只显示我的 log4j 日志 在我的 log4j properties 文件中 我将根记录器日志记录级别设置为 ERROR 然后
  • 如何在Vue中获取输入字段值

    我是 Vue 新手 我需要一些帮助来从输入字段获取值 在我的表格中 我有
  • 从 Vue CLI 切换到使用 Spring-Boot 作为后端的 Vite,开发服务器未按预期工作

    有多种方法可以将 Vue 项目集成到 Spring Boot 项目中 使用基于 webpack 的构建工具 例如 vue cli 我已经通过以下方式成功完成了几次 配置outputDir构建过程的输出被放置在例如 static dist 最
  • 如何在 Atom 中启用 .vue 文件的语法突出显示?

    我开始使用 Vue js 我遇到的第一个问题是我的 IDE Atom 无法美化我的 vue 文件 这一切都只是白色的文字 如何让 Atom 正确突出显示 vue 文件 语言 vue https atom io packages langua
  • Vue js - 在同一级别的两个组件内传递数据

    我有需要从一个传递的数据component1到另一个component2 我不使用vuex or router 组件树 Parent Component1 Component2 从一开始component1我发出 ajax 请求 检索信息并
  • npm run dev 和 npm run production 之间的区别

    我对 Laravel 和 vue js 很陌生 请让我知道它们之间有什么区别npm run dev and npm run production 这和环境有关系吗 npm run dev创建源映射并且不会缩小 js css 这使得调试和查找
  • 如何将 Jitsi Meet 添加到 Vuejs

    我已在 public html 的正文中加载了 jitsi meet 脚本 并且我有一个组件 如下所示
  • Mapbox JS SDK CSS样式表导致地图消失

    我在 VueJS 应用程序中使用 Mapbox JavaScript SDK 我可以毫无问题地显示地图 现在我想添加一些标记 我懂了在本页 https docs mapbox com mapbox gl js api 您需要先导入 CSS
  • 我们可以在运行时更改 log4j 的日志记录级别吗

    我有一个问题 我想在运行时更改 log4j 的日志记录级别 我已经尝试了 log4j properties 文件的很多操作 我还尝试编写一段代码 在特定时间后再次读取属性文件并再次配置记录器 但问题是 我想将一个 API 调用的日志记录级别
  • 具有共享日志配置的 Gradle 多项目

    是否有一种标准方法可以在 gradle 项目布局中的所有子项目之间共享日志记录配置 例如 log4j 或 logback 我现在做的就是复制一份logback xml or log4j properties in src main reso
  • 从组件传递数据

    我对 Vue 相当陌生 我正在尝试将数据从组件传递到视图 我不确定我是否在使用props正确的 我有一个对话框 当我保存时 我想将数据插入数据库 我也想重复使用addCustomer function 这就是为什么我没有将该函数放置在组件中
  • Vue 监听 Vuex 提交吗?

    有没有一种方法可以监听 Vuex 提交 而不观察任何随提交而更改的属性 只是简单地找出是否发生了提交 我有一个 Filter 组件 想将其放入 NPM 包中 但我已经有一个用例 在该用例中 我希望设置一个 cookie 在选择过滤器时存储过
  • 用变量字符串设置槽的简单方法?

    有许多slot例子 但没有克莱尔和简单 因为我需要 我需要类似的东西 var x Hello slot x 这就是我需要的 在一个具体的例子中 https jsfiddle net 2qdh3x3v https jsfiddle net 2
  • Laravel Vue 组件只能传递数字?

    在我的 UserMenu vue 中我写道 export default props nameVal data return 并在blade php中

随机推荐

  • flask+APScheduler定时任务的使用

    APScheduler定时任务使用以及在flask中的调用 APScheduler简介 组成部分 调度器 安装 普通使用安装 结合flask使用安装 使用 添加job add job参数详解 interval 间隔时间 每隔一段时间执行 d
  • Linux下实现编写汇编程序

    本学期的微机原理课程上机使用的是MASM汇编器 上课时使用的是Windows上的DOS 而Linux中的汇编工具是nasm 具体的可以点击链接 http os 51cto com art 201101 243138 htm 这里写代码片 下
  • C++11智能指针的基本原理及使用

    介绍 智能指针是一个类 用来存储指向动态分配对象的指针 负责自动释放动态分配的对象 防止堆内存泄漏 动态分配的资源 交给一个类对象去管理 当类对象声明周期结束时 自动调用析构函数释放资源 分类 auto ptr 已弃用 使用unique p
  • 神经网络算法和遗传算法,数据挖掘神经网络算法

    神经网络算法与进化算是什么关系 应该没有太大的关系吧 我对遗传算法了解一点 遗传算法主要用来优化神经网络第一次运行时所用的连接权值 因为随机的连接权值往往不能对针对的问题有比较好的收敛效果 Matlab神经网络工具箱自动生成的初始权值其实已
  • Tracy 小笔记 Vue - 网络模块封装(axios)

    安装 axios 和 引入 安装 npm install axios save 引用 import axios from axios 网络请求可以测试的几个接口地址 http httpbin org get http 123 207 32
  • Linux中的JDK安装和配置

    Linux中的JDK安装和配置 1 查看是否已安装JDK yum list installed grep java 2 卸载系统Java环境 yum y remove java 1 8 0 openjdk 3 卸载tzdata java y
  • 那年的夏天很笛子

    原文 salance moon spaces live com 在某个阶段 我想应该是时候把至今为止影响自己走上美工 设计 程序之路的历程整理一下了 但是下笔的时候才发现 其实这几乎成了我童年的回忆录 因为程序暂且不算 美工 设计就是我人格
  • Connect函数阻塞

    1 采用select 在学习嵌入式Linux网络编程中 很多同学都发现了一个问题 那就是调用connect函数时 如果服务端关闭 客户 端调用connect 函数时 发现阻塞在那里 而且利用ctrl c信号去停止客户端程序时 需要等待一个较
  • git:一次回滚多个commit

    说明 独立分散的commit共同回滚 git revert n sha 1 git 单次commit对应的sha 1值 sha 1 sha 1 ps n代表不会生成新的commit 如果想直接生成commit请去掉 n 最近连续的coomi
  • hr谈薪资后说请示领导_如何巧妙回答面试中的薪资问题呢?

    好不容易挺过了群面 单面 没想到在HR面被薪资问题打个措手不及 你的期望薪资是多少 说低了总觉得委屈自己 说高了又怕offer不保 好不容易在前面几轮面试积攒的自信 在这个问题上就变成 emm差不多就行吧 然后面试一结束就开始无限后悔 对于
  • 【ML特征工程】第 1 章 :机器学习管道

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • STM32F407 单片机+DMA+环形缓冲区+GPS报文解析

    本文采用DMA 环形缓冲区对GPS报文进行解析 思路是通过DMA中断接收到GPS报文后 存放到环形缓冲区 然后在主程序中解析GPS报文 解析GPS报文的关键是 将环形缓冲区中的字节转换成字符串 然后在字符串中查找GPS报文头标识 例如 GP
  • Block头部解析

    Block解析介绍了Block的各个组成部分 魔法数 块大小 块头部 交易个数 交易 本文将详细介绍块魔法数和块头部的各个组成部分 魔法数 魔法数是比特币客户端解析Block数据时的识别码 比特币正式网络的魔法数是0xD9B4BEF9 不同
  • 地图标识符号大全_资源小结:分省地图查询(9.1版)

    公众号首页回复关键字 分省地图 或通过菜单栏可以快速找到本页 本页内容不断更新 建议收藏起来备查 北京市 北京市最新行政区划图 行政统计表 图集下载 北京市地图集 分区 北京市人文地图 高清版 北京经典旅游线路图 北京城区地图 一亿像素高清
  • vue3和ts使用

    Vue3和TypeScript是两个非常流行的前端技术 它们都有着自己的优点和特点 Vue3是Vue js的最新版本 它带来了很多新的特性和改进 包括更好的性能 更好的开发体验和更好的可维护性 TypeScript是一种静态类型语言 它可以
  • 一文搞懂STM32 PWM配置

    本文主要介绍通过CubeMX对STM32G070CBT6进行配置生成PWM波 内容包括PWM的基本概念 PWM的应用 PWM产生的方法 STM32 PWM波配置详解 1 PWM PWM 英文名Pulse Width Modulation 是
  • 02-不得不了解的js特性

    一 回顾js特性 针对浏览器端js 它有哪些特性 弱类型 解释型 1 弱类型 所谓强类型 就意味着在声明变量的时候 需要确定数据类型 一经确定就不能改变 而弱类型 在声明变量的时候 是无需声明变量的类型 变量的类型有其值来决定 并且是可以随
  • 使用pyecharts出现 'ModuleNotFoundError: No module named 'pyecharts_snapshot' 异常

    使用pyecharts时 出现 ModuleNotFoundError No module named pyecharts snapshot 试了几次都无法解决 突然想到 pyecharts snapshot 会不会也是一个第三方库 毕竟异
  • MySQL 列属性修改操作

    1 mysql中修改字段长度 sql view plain copy ALTER TABLE tb article MODIFY COLUMN NAME VARCHAR 50 这里的tb article为表名 NAME为字段名 50为修改后
  • Vue 组件的单元测试

    1 基本的示例 单元测试是软件开发非常基础的一部分 单元测试会封闭执行最小化单元的代码 使得添加新功能和追踪问题更容易 Vue 的单文件组件使得为组件撰写隔离的单元测试这件事更加直接 它会让你更有信心地开发新特性而不破坏现有的实现 并帮助其