本文是一份分步指南,涵盖了 Vue.js 测试基础知识,并为读者解释了如何测试基于 Vue.js 的网站和移动应用程序。
“当 Vue 的用户数量达到一定数量时,它就变成了一个社区。突然间,所有这些人都指望我了:贡献者、用户、教育工作者、学生……它变得比我想象的要大。” – 尤文
这是一位开发者对 2014 年发布的 JS 框架的自白,该框架如今已被超过150 万用户使用。如果我们考虑一个框架有多新,它在网站开发中就变得很重要。随着开发人员慢慢接受 Vue,Vue.js 测试的问题在组织中变得更加有趣。
该框架在一个不是很流行的地方,所以每个问题都可以在社区渠道上找到,并且不是新到还处于试验阶段。当我们看到使用 Vue 构建的大型应用程序时,我们知道 Vue.js 测试的相关性只会随着时间的推移而增加。
所有这些事实使本指南成为拼图的重要组成部分,最终将指导您向世界发布基于 Vue.js 的 Web 应用程序。
什么是 Vue.js?
Vue.js 是一个用于构建复杂或简单用户界面的框架。它于 2014 年发布,如今被近 1% 的网站使用。它是轻量级的,构建在 html、css 和 JAVAScript 等主要 Web 组件之上。
它使用基于组件的模型视图框架范例,允许将模块构建为松散耦合和连接的组件。这有助于将复杂的模块分解为应用程序的其他部分也可以重用的小组件。
Vue.js 表达其基于组件的功能的一个小例子如下:
import { createApp } from 'vue'
createApp({
data() {
return {
counter: 0
}
}
}).mount('#app')
HTML 代码:
<div id="app">
<button @click="count++">
Count is: {{ count }}
</button>
</div>
在这里,我们通过代码看到了 HTML 中声明式渲染的一个重要概念{{count}}。通过声明式渲染,我们指出了模板渲染部分,我们可以在其中使用声明性语法或模板语法直接渲染数据,这也是 Jinja 2 模板引擎中的双括号。这是 Vue 的一个重要属性,可以在快速开发和最小化代码方面派上用场。
第二个属性是反应性,自动对 JavaScript 代码中的更改做出反应。然后,更改会反映在 DOM 中,而无需编写任何额外的代码。然而,这是对反应性的简要概括,需要详细讨论。由于本指南围绕测试 Vue 组件展开,让我们改天再讨论。
Vue.js 基于组件的系统概述
基于组件的系统的基本思想是将较大的事物划分为较小的单元,并孤立地关注每个单元。这有助于分解一个更大的问题,并专注于如果立即采用整个系统可能会遗漏的细节。当我们开发被分成基于组件的树的简单 HTML 页面时,也可以看到这一点:
组件树
在 Vue 中,我们通过将每个组件保存到其文件中并将其逻辑作为扩展来执行类似的操作.vue。
为了理解 Vue.js 中组件的最小示例,让我们创建一个小网页,如下所示:
<div>
<h1> Hi This is Div 1.</h1>
</div>
<div>
<h1> Hi This is Div 2.</h1>
</div>
在 Vue 的app.js文件中,我们将创建一个组件来演示可重用性,如下所示:
Vue.component(<component_name>, object)
在编写代码时,将其替换为您要放置的组件的名称:
Vue.component(‘vcomp’)
我们将放下一个简单的模板来替换对象:
Vue.component(‘vcomp’, {
template: “<h2> Hi this is a Vue Component </h2>”
});
在这里,模板部分采用您希望在屏幕上呈现此组件时显示的 HTML 模板。
有了这段小代码,我们的组件就可以在我们一开始编写的 HTML 页面中实现了。由于此组件由名称“ vcomp ”引用,因此让我们将其插入 div 块中,如下所示:
<div>
<h1> Hi This is Div 1.</h1>
<vcomp><vcomp>
</div>
<div>
<h1> Hi This is Div 2.</h1>
<vcomp></vcomp>
</div>
Vue 在这里要做的是用 中描述的组件模板替换 vcomp 标签app.js。结果,我们得到一个小网页如下:
小网页
如果我们检查这个网页,我们可以检查 HTML 代码是否已被 Vue 中提供的模板替换:
模板
一个简单的问题是代码已经变得可重用,但不能根据我们的选择进行定制。在 Web 开发中,您可能有许多具有相同代码的元素。我们上面的例子可以满足的需求。然而,我们可以有更多的代码,它们不相同但相似。例如,“Hi, I am Harish”和“Hi, I am Jack”是两个相似元素,与“Hi, I am”的相似度为 75%。如果我们能找到一种方法将数据放入此模板中,我们就会拥有一个很好的组件。
这是通过附加到 Vue 组件的数据对象来完成的。现在,我们修改后的视图为:
Vue.component(‘vcomp’, {
template: “<h2> Hi I am </h2>”
});
这表示将保持不变的部分。一个数据对象写成:
Vue.component(‘vcomp’, {
template: “<h2> Hi I am </h2>,
data: function(){}”
});
在函数部分,你可以编写你想要执行的函数。对于我们的示例,您需要返回名称以将其作为:
Vue.component(‘vcomp’, {
template: “<h2> Hi I am {{name}}.</h2>,
data: function(){
return {
name: “Harish”
}
}”
});
另外,请注意我们在模板中放置的附加项{{name}},我们希望在返回时放置名称。
我们需要做的最后一件事是决定何时调用此函数以及如何调用它。虽然有很多方法可以实现这一点,但为了演示,我将把on:click事件附加到一个按钮上,单击该按钮可以调用该函数。
修改后的代码则变成如下:
Vue.component(‘vcomp’, {
template: “<h2> Hi I am {{name}}. <button v-on:click = “changeName”></button></h2>”,
data: function(){
return {
name: “Harish”
}
},
methods: {
changeName: function(){
this.name = ‘Ashley’;
}
}
});
这里要注意的两个修饰元素是“ methods ”和“ button ”。运行这段代码,你会得到一个按钮,点击它的名字“嗨,我是”变成“嗨,我是阿什利”。
单元测试:概述
单元测试是测试软件的支柱之一,另一个是集成测试和端到端测试。通常,软件测试从单元测试开始,尤其是当 TDD 作为一种开发方法得到促进时。
单元测试将软件分解成更小的单元,因此更容易关注更小的部分及其细节,调试也变得容易得多。这个定义可能看起来类似于我们在上面的组件定义中讨论的内容。
实际上,它们都有相似的根源,但它们所服务的目标却不同。由于组件在 Vue 应用程序中也是较小的单元,因此测试人员执行单元测试的工作变得容易得多,并且针对特定区域。因此,Vue 组件中的单元测试是 Vue 测试人员之间的热门话题。
请注意,这不应与“测试组件”混淆,因为单元测试适用于基于 Vue 的应用程序。单元测试仍然意味着测试预期输出的功能或类,但只针对应用程序的一小部分。
当我们开始只测试 Vue 应用程序的组件时,例如它如何挂载或呈现,我们称之为 Vue 中的组件测试。但是,这并不意味着单元测试不涵盖“仅”组件。在某些情况下,它可能会,而在少数情况下,它可能不会。
如何开始在 Vue.js 中进行单元测试
在 Vue.js 测试指南的这一部分,我们将在 Vue 中进行单元测试,这与 Web 应用程序中的单元测试不同。在这里,我们将只关注如何对使用 Vue 编写的应用程序的部分进行单元测试。
考虑到基于 Vue 的功能是如何工作的,我们的目标是对两种类型的功能进行单元测试。
可组合物
成分
因此,我们可以将这一节分为两个逻辑部分。
如何在 Vue Composables 中执行单元测试
可组合项的概念随着 Vue 的第 3 版发布而引入,旨在消除导致复杂组件和混合的所有 Vue 2 弱点。Vue 可组合是指那些使用 Vue 的组合 API 的函数。此 API 是针对随着时间的推移变得太大且难以维护的组件的解决方案。
例如,假设我们有一个组件可以通过搜索列出某些产品。稍后,我们需要通过应用某些过滤器来在此搜索中提供更多功能。几天后,我们可能会添加另一个搜索功能。做所有这些,我们可能会制造一个非常大和复杂的组件,它会变得非常难以维护。
相反,我们可以使用组合 API,它们是从这些组件调用的可重用函数,并消除了大选项和数据。在此示例中,我们可以创建search()、sort()、filter()、advanceFilter()等,并在主组件需要时调用。
可组合项可以依赖于以下三个 API 中的任何一个:
生命周期
注入
反应性
在这三者中,如果使用反应性如下:
import { createApp } from 'vue'
createApp({
data() {
return {
counter: 0
}
}
}).mount('#app')
这可以通过直接匹配预期结果和实际结果来测试,也称为测试中的断言。然而,如果使用 lifehooks 和 inject,测试人员需要将这些元素“包装在主机组件内”,解释这可能会使我们偏离实际的单元测试部分。
如何在 Vue 组件中执行单元测试
Vue 组件中的单元测试旨在测试应用程序中组件提供的功能。虽然他们应该以组件为目标,但他们应该只关注与这些组件相关的功能和事件,而不是深入研究代码的正确性。
在 Vue.js 中执行单元测试时需要注意的重要一点是,不应断言组件实例的私有状态,因为它可能会因任何实现更改而中断。单元测试的主要重点应该是验证某个功能或事件或交互的输出。
Vue.js 组件的单元测试工具
虽然有很多工具和插件可用于对 Vue.js 组件进行单元测试,但 Vue 官网仅推荐两个工具:
齿轮
柏
Vitest 是基于节点的工具,而 Cypress 是基于浏览器的工具。基于节点的工具可能不如基于浏览器的工具高效;因此,在这种情况下,Cypress 可能是首选。但是,它会产生一定的成本。由于 Vitest 是一种无头工具并且是基于节点的,因此它可以比 Cypress 更快地执行测试。
正如 Vue 所说,“Cypress 可能比 Vitest 慢几个数量级”, 这可能是一个值得关注的问题。因此,测试人员在使用 Vue.js 进行单元测试时必须谨慎工作。
要将 Vitest 添加到您的项目中,您可以直接使用 npm 包管理器将其添加到一个命令中:
npm install -D vitest happy-dom @testing-library/vue
在此之后,我们需要更新 Vite 配置以添加测试选项块:
import { defineConfig } from 'vite'
export default defineConfig({
test: {
}
})
完成后,我们可以将测试写入一个名称以*.test.js. 该文件可以放在项目根文件夹中的测试目录中。您还可以将此文件放在源文件旁边的测试目录中。
现在测试用例已经写好了,只需添加测试脚本如下package.json:
{
// ...
"scripts": {
"test": "vitest"
}
}
现在使用一个简单的 npm 命令运行这些测试:
npm test
安装库
挂载库必须挂载组件,以便可以模拟用户事件,并且可以使用类似用户的操作调用单元测试。这些库由 Vue 提供,推荐用于 Vue 组件的单元测试。
@testing-library/vue
@vue/test-utils
在这两者中,@vue/test-utils是一个低级库,@testing-library/vue建立在它之上。因此,从这个事实可以明显看出,@vue/test-utils深入研究 Vue API 的实现细节,同时@testing-library/vue远离它,只关注最终用户如何使用软件。对于测试人员来说,这完全取决于他们根据情况选择更喜欢哪一个。然而,两者的混合搭配可以产生最好的结果。
如何在 Vue.js 中运行单元测试
Vue.js 中的单元测试可以使用 Vue Test Utils 库运行,这是 Vue.js 的官方单元测试库。它可以与 Jest、Mocha 和 Karma 等测试运行器一起使用,也可以在没有带有 jsdom 的测试运行器的情况下使用。Vue.js 推荐使用 Jest 进行单元测试;因此,我们将在这里遵循相同的模式。
要使用 jest 安装 Vue 测试工具,请运行以下两个命令。
安装cli-plugin-unit-jest运行 Jest 测试:
vue add unit-jest
安装 Vue 测试工具:
$ npm install --save-dev @vue/test-utils
现在,我们可以对我们开始 Vue.js 测试指南的初始代码做一个简单的小测试:
template: `
<div>
<button @click="count++">Add up</button>
<p>Clicks: {{ counter }}</p>
</div>
`,
data() {
return { counter: 0 }
}
}
现在,我们首先需要定位此按钮并返回一个包装器以继续下一步。这是通过以下代码实现的:
const button = wrapper.find('button')
现在,找到p这个按钮内的标签:
const countertext = wrapper.find('p')
然后,我们需要提供一些异步行为来等待点击发生,这可以引导我们触发我们的代码:
expect(text.text()).toContAIn('Clicks: 0')
await button.trigger('click')
expect(text.text()).toContain('Clicks: 1')
在这里,正如我们提到的,使用了异步行为,这是 Vue 中一个很深的话题。希望了解更多信息的人可以参考 Vue.js 文档中关于异步行为的官方页面。运行上面的测试暴露了按钮的功能和包含它的模块。
在执行 Vue.js 测试时,许多组织在为 windows、macOS、Android 和 IOS 等多个平台构建 Web 和移动应用程序时面临严峻挑战。开发人员和 QA 团队面临着创建内部测试基础架构以覆盖所有浏览器、设备和操作系统的主要挑战,这是一种乏味且昂贵的方法。您仍然需要持续管理操作系统更新,这是非常不切实际的。
然而,基于云的测试平台使这变得容易。
Vue 中的 Mount 与 ShallowMount
在通过 vue test utils 在 Vue 中执行单元测试时,你会经常遇到mount()和shallowMount()在示例中或阅读其他人的单元测试代码。测试人员将使用这两种方法在 Vue 中创建单元测试。
Vue 中的函数mount()将 Vue 组件作为参数并返回该组件的包装器。使用这个实例包装器,测试人员可以与组件交互,因为它会捕获 DOM 并为您呈现它。
该shallowMount()函数的工作方式也类似,有助于与传递的组件进行交互。它们之间唯一的区别是shallowMount()不渲染子组件。而mount()将渲染传递的组件及其所有子组件。
因此,它们在不同的场景和用例中都是首选。最重要的是,当您需要隔离测试任何组件并需要测试更改对孩子的影响时,shallowMount就要使用它。否则,如果涉及儿童,那么你应该去mount()。这将使您的单元测试用例保持独立,并清楚地说明它们的目标。
结论
Vue 是一个框架,在网站开发的用户界面市场中出现了显着增长。凭借其类似于 React 的基于组件的机制,Vue 试图将繁重的模块分解为更小的组件,这些组件不仅有助于开发,也有助于测试。
本 Vue.js 测试指南讨论了网站的测试部分,该网站包含基于 Vue 的元素,特别侧重于单元测试。Vue 有丰富的 API 集合,有助于组件的单元测试,本指南中讨论了一个演示。
对于 Web 开发人员和测试人员,我希望本指南能为您的下一个单元测试项目提供很好的参考。对于任何反馈和建议,请在评论部分或通过电子邮件告诉我们。感谢您花宝贵的时间给这篇文章。