本文是一份分步指南,涵蓋了 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 開發人員和測試人員,我希望本指南能為您的下一個單元測試項目提供很好的參考。對于任何反饋和建議,請在評論部分或通過電子郵件告訴我們。感謝您花寶貴的時間給這篇文章。