1. 程式人生 > >如何對第一個Vue.js元件進行單元測試 (下)

如何對第一個Vue.js元件進行單元測試 (下)

我們的首次測試

   讓我們來寫首個測試。我們首先需要使用shallowMount手動掛載我們的元件,並將其儲存在我們將執行斷言的變數中。我們還可以通過propsData屬性傳遞道具作為物件。

   已安裝的元件是一個物件,它有一些實用方法:

如何對第一個Vue.js元件進行單元測試 (下)

   然後,我們可以寫第一個斷言:

如何對第一個Vue.js元件進行單元測試 (下)

   讓我們來分析一下這裡發生了什麼。首先,我們使用Jest的expect函式,它將我們想要測試的值作為引數。在我們的例子中,在父級上用findAll方法來獲取具有活動類的所有元素。這將返回一個WrapperArray,包含Wrappers陣列的物件。

   一個WrapperArray有兩個屬性:父級(包含的Wrappers)和長度(Wrappers的數量)。後者是我們需要擁有預期數量的stars。

   expect函式還返回一個物件,我們可以在其上呼叫方法來測試傳遞的值。這些方法稱為匹配器。在這裡,我們使用toEqual匹配器並將其作為引數傳遞給期望值。該方法返回一個布林值(boolean),這是測試通過或失敗的原因。

   總而言之,在這裡,我們期望在父級中找到的具有活動類的元素的總量應等於3(我們分配給等級道具的值)。

   在您的終端中,執行您的測試:

如何對第一個Vue.js元件進行單元測試 (下)

   你應該看到它通過。 

模擬使用者輸入

   Vue Test Utils可以輕鬆模擬真實使用者最終在實際中所做的事情。在我們的用例中,使用者可以點選stars來切換它們。我們可以在測試中使用觸發器方法偽造它,並排程各種事件。

如何對第一個Vue.js元件進行單元測試 (下)

   在這裡,我們首先用findAll獲取第四顆star,它在傳遞的索引(從零開始的編號)中從WrapperArray返回一個Wrapper。然後,我們模擬它上面的點選事件- 我們模仿點選第四顆star的使用者行為。

   由於我們將prop等級設定為3,因此在我們點選之前,第四個star應該處於非活動狀態,因此click事件應該使其處於活動狀態。在我們的程式碼中,這由一個活動類表示,我們僅在它們被啟用時附加在star上。我們通過呼叫star上的classes方法來測試它,它將類名作為字串陣列返回。然後,我們使用toContain匹配器來確保活動類在這裡。

設定和拆解

   由於我們觸發了對元件的點選,我們已經改變了它的狀態。問題是我們在所有測試中使用相同的元件。如果我們改變測試順序並將其移到第一個位置會發生什麼?然後第二次測試將失敗。

   在測試時,你不想依賴諸如命令這樣的脆弱的東西。測試套件應該是強大的,並且除非您破壞API,否則理想情況下現有測試應該不會改變。

   我們希望確保始終有一個可預測的父級來執行斷言。我們可以通過設定和拆卸功能實現這一目標。這可以幫助我們在執行測試之前初始化,然後進行清理。

   在我們的例子中,有一種方法可以是在每次測試之前建立我們的父級並在之後銷燬它。

如何對第一個Vue.js元件進行單元測試 (下)

   正如他們的名字所暗示的那樣,beforeEach和afterEach分別在每次測試之前和之後執行。通過這種方式,我們可以100%確定每當我們執行新測試時,我們都能使用新的父級。

測試的特殊識別符號

   將選擇器與樣式和其他目的(例如測試鉤子)混合絕不是一個好主意。

   如果更改標籤名稱或類怎麼辦?

   如果您在要測試的元素上沒有特定的識別符號,例如計數器,該怎麼辦?

您不想使用無用的類汙染您的生產程式碼。為測試提供專用鉤子會更好,例如專用資料屬性,但僅限於測試期間。這樣就不會在最終構建中留下一團糟。

   處理此問題的一種方法是建立自定義Vue指令。

   [Vue.js](https://www.bdgstore.com.cn/portal/article/index/id/210.html)例項有一個指令方法,它接受兩個引數- 一個名稱,以及在DOM中注入時元件生命週期的鉤子函式。如果您不關心特定的鉤子,也可以傳遞單個函式。

   讓我們在src /中建立一個名為directives的新目錄,並新增一個test.js檔案。我們將在我們的指令中匯出我們想要傳遞的函式。

如何對第一個Vue.js元件進行單元測試 (下)

   一個指令鉤子可以帶幾個引數,在我們的例子中,我們只需要前兩個:el和binding。el引數引用指令繫結的元素。binding引數是一個物件,它包含我們在指令中傳遞的資料。這樣我們就可以按照自己的意願操縱元素。

如何對第一個Vue.js元件進行單元測試 (下)

   我們將一個物件傳遞給我們的指令,因此我們可以從data-test-開始生成資料屬性。在處理函式中,我們繫結的每個屬性,並在元素上設定一個基於名稱和值的資料屬性。

   我們將一個物件傳遞給我們的指令,因此我們可以從data-test-開始生成資料屬性。在處理函式中,我們反覆繫結每個binding屬性,並在元素上設定一個基於名稱和值的資料屬性。

   現在我們需要註冊我們的指令,以使用它。我們可以在全球範圍內進行,但在我們的情況下,我們只會在本地註冊- 就在我們的Rating.vue元件中。

如何對第一個Vue.js元件進行單元測試 (下)

   我們的指令現在可以在v-test名稱下訪問。嘗試在計數器上設定以下指令:

如何對第一個Vue.js元件進行單元測試 (下)

   現在使用開發人員工具檢查瀏覽器中的HTML。你的面板應該是這樣的:

如何對第一個Vue.js元件進行單元測試 (下)

   開始工作了!現在,我們在開發模式和構建專案時都不需要這個。此資料屬性的唯一目的是能夠在測試期間定位元素,因此我們只想在執行它們時進行設定。為此,我們可以使用Webpack提供的NODE_ENV環境變數,這是為我們的專案提供動力的模組捆綁器。

   當我們執行測試時,NODE_ENV被設定為'test'。因此,我們可以使用它來確定何時設定測試屬性。

如何對第一個Vue.js元件進行單元測試 (下)

   在瀏覽器中重新整理您的應用並再次檢查計數器:資料屬性已消失。

   現在我們可以對我們需要定位的所有元素使用v-test指令。讓我們從前面開始測試:

如何對第一個Vue.js元件進行單元測試 (下)

   我們用[data-test-id =“star”]替換了.star選擇器,它允許我們在不破壞測試的情況下更改類以用於演示目的。這也是單一責任原則和鬆散耦合的好處之一 。

   我們是否還應該為我們測試的類使用這些鉤子?

   在將此指令設定為要測試的目標元素之後,您可能想知道是否還應該使用它們來替換我們主動查詢的類。讓我們看看第一次測試的斷言:

如何對第一個Vue.js元件進行單元測試 (下)

   我們應該對具有活動類的元素使用v-test,並在斷言中替換選擇器嗎?好問題。

   單元測試都是關於一次測試一件事。it函式的第一個引數是一個字串,我們用它來描述我們從消費者的角度做的事情。

   包裝我們斷言的測試表示渲染一個類活動等於prop.grade的star列表。這是消費者的期望。當他們將數字傳遞給grade屬性時,他們希望獲得相同數量的活躍或選定的star。然而,在我們元件的邏輯中,活動類正是我們用來定義這個特徵的東西。我們根據具體情況進行分配,因此我們可以在視覺上區分活躍的stars。在這裡,這個特定類的存在正是我們想要測試的。

   因此,在決定是否應該使用已有的選擇器或設定v-test指令時,請問自己一個問題:我在測試什麼,並且使用此選擇器對業務邏輯透檢視有意義嗎?

它與功能或端到端測試有何不同?

   首先,單元測試元件可能看起來很奇怪。為什麼要對UI和使用者互動進行單元測試?這不是功能測試嗎?

   在測試元件的公共API(也就是從消費者的角度來看)和從使用者角度測試元件之間存在著根本但微妙的差異。首先,讓我們強調一些重要的東西:我們正在測試定義良好的JavaScript函式,而不是UI。

   當您檢視單個檔案元件時,很容易忘記元件編譯成JavaScript函式。我們沒有測試底層的Vue機制,它從這個函式中導致了面向UI的副作用,比如在DOM中注入HTML。這就是Vue自己的測試已經解決的問題。在我們的例子中,我們的元件與任何其他函式沒有區別:它接受輸入並返回輸出。這些原因和後果是我們正在測試的,而不是其他任何東西。

   令人困惑的是,我們的測試與常規單元測試略有不同。通常,我們寫的東西如下:

如何對第一個Vue.js元件進行單元測試 (下)

   這裡沒有爭論。輸入和輸出資料,這就是我們所關心的。對於元件,我們期望呈現視覺的東西。我們正在通過虛擬DOM並測試節點的存在。這也是您使用Selenium或Cypress.io等工具進行功能或端到端測試的方法。那有什麼不同呢?

   通過單元測試,我們正在測試單獨的行為。通過功能或端到端測試,我們正在測試場景。單元測試可確保程式單元的行為符合預期。它面向元件的消費者- 在軟體中使用該元件的程式設計師。功能測試從使用者角度確保功能或工作流的行為符合預期 。