天天看點

第一章 介紹Vue應用的測試第一章 介紹Vue應用的測試

第一章 介紹Vue應用的測試

本章涉及
  • 什麼是測試
  • 為什麼測試是有用的
  • 單元測試、e2e測試和快照測試之間的不同
  • Vue核心概念

作為一個開發者,你想釋出沒有bug的代碼。如果你在周一早上發現你周五修改的代碼在生産環境上出現問題,那沒有比這更遭的了。想要確定你的應用能正确地工作,唯一的辦法就是進行測試,是以你完全學會如何測試應用是至關重要的。

一個好的測試方案,能提高開發速度、強化代碼品質并且限制你應用中的bug。而不好的測試方案會導緻項目出現問題。本書将會教你有效地測試Vue應用,確定你能從測試中收益和避坑。讀完本書你将會成為一名Vue測試高手,并且準好好随時測試你遇到的任何Vue應用。

要學習如何測試Vue應用,你将從頭到尾的為“極客新聞”的克隆應用編寫一個測試套件。”極客新聞“将會像其他大型應用一樣,使用Vue、Vuex、Vue-router和服務端渲染。

不單單要教你測試技術,我還要教你我這些年測試方面的思維模式和方案。全書我将會提供訓練你測試技術的建議。

第一章是Vue應用測試的基礎知識。我将會給你關于通用測試全方面的概覽、書中你會學到的不同類型的測試、以及你将要編寫的”即可新聞“應用。最後,我會解釋一些Vue的核心概念,來確定我們不會雞同鴨講。

那第一件事,就是給測試下定義。

1.1 給測試下定義

任何有價值的學術論文會在深入讨論前定義它使用的概念。是以,就像一個好的學者一樣,我将會在教你關于不同測試技術前,定義我所指的應用測試。

應用測試一個簡單的定義就是檢查應用正确行為的過程。無疑你應該檢查的應用行為的正确性,但當讨論到不同的測試技術時,這個話題就變得有趣了。

有兩個主要的方案來進行測試:手工測試和自動化測試。手工測試就是你自己和應用互動,自己檢查程式是否正确工作。自動化測試通常做法是寫程式來為你執行檢查。

本書絕大部分是關于自動化測試。但是要了解自動化測試的收益,你必須了解手工測試。

1.1.1 手動測試

每一位合格的開發者都手工測試代碼。它是寫完源代碼後合乎邏輯的下一步,就像咀嚼完食物的下一步是吞下它一樣。

想象你正在建立一個登入表單。當你寫完源代碼後,你不會直接關閉你的編輯器然後告訴你上司說你寫完表單了,不,你會打開浏覽器,填寫表單,然後確定它能正确完成登入過程。換句話說,你會手工測試代碼。

手工測試對于小項目來說是很合适的。如果你有個待辦清單應用,你能在2分鐘内手工測試完成,你就不需要自動化測試。但是如果你的應用成長到某個量級時,依賴手工測試會變成一項負擔。

讓我和你講講我工作時的第一個大型JavaScript應用,它非常的亂。你有沒有聽說過意大利面條代碼?代碼就像各種類型的意大利面混雜卷在一起一樣,非常難去梳理應用邏輯,并且也沒有任何自動化測試。不必說,裡面有很多bug。如果要解決bug,我們必須在釋出前手工測試應用。每周三我們會喝掉很多咖啡,打開一個使用者體驗清單進行測試,并且蜷縮在筆記本電腦前,花4小時時間執行一套指令,真的非常痛苦。

定義 使用者體驗清單,就是使用者在應用程式上會經曆的每一步的清單。例如,打開應用、填寫表單、點選送出。

考慮到我們要花10%的開發時間來手工測試應用,你可能會像我們會在生産環境上逐漸消除bug,不,應用還是充斥着bug。原因是,手工測試大量的功能是非常困難的,它很容易讓人失去耐心并且遺漏測試某些點。

有一次,我在測試一個使用者體驗的時候,我不小心遺漏檢查了一個是否會顯示音樂路徑的點選按鈕,其他開發人員也肯定忘記測試這個功能,因為它線上上存在了整整幾個月了!

盡管一些手工測試的時間被用在發測試新功能上,但更多的時間被花在測試舊功能是否正常運作,這種測試就是衆所周知的回歸測試。回歸測試對人來說是一件困難的事情,它們重複且乏味,還需要很多注意力而且沒有創造價值。簡單來說,他們很無聊,幸運的是,計算機很擅長做這種事情,這就是自動化測試的作用!

1.1.2 自動化測試

自動化測試就是通過程式來檢查你的軟體是否工作正常。或者說,你寫額外的代碼來測試你的應用代碼。在測試代碼被寫出來後,你可以花最少的力氣,想幾次就幾次地測試你的應用。

你可以使用一些不同的技術來編寫自動化測試。你可以編寫浏覽器中的自動化代碼,直接而調用你源碼中的函數;或者比較你應用渲染後的快照。這些技術有不同的收益,但它們都有一個共同點:它們比你手工測試要省時間。

在前面章節中,我說我參與過沒有測試的應用,它的問題之一就是每次我們要釋出新版本,都需要花上進行4小時的手工測試。在我加入團隊不久,CTO就決定我們應該寫自動化測試來代替人的工作。一段時間後,我們測試所花費的時間從4小時人工工作減少到了20分鐘的自動化工作。

有了這次經驗,對應大型項目,我總是一開始就寫好自動化測試。馴服一匹從小就跟着人生活的馬總是要比培養一匹囚禁起來的野馬要容易。在本書中,你将會學習通過編寫測試來建立一個簡單的應用。

自動化測試對于檢查你的應用是否仍然正常工作非常有用。它也令檢查應用代碼的變化更加簡單。讓我們來看看一個使用自動化測試的真執行個體子——在GitHub測試PR(pull request)。

1.1.3 從GitHub上PR測試

GitHub是一個Git托管倉庫網站。很多開源項目比如Vue都在GitHub上托管,很多我就職過的公司都把他們的代碼維護在GitHub的私倉上。

定義

Git是一個版本控制系統。我這裡假定你曾經用過,并且熟悉合并、分支、送出這些概念。如果你不熟悉,你可以在Git文檔檢視學習。

PR是GitHub工作流(GitHub flow)的一部分,在開發者将獨立的分支合并到主分支之前,它提供一個cv(code review,代碼評審)的機會。

說明

如果你不熟悉GitHub工作流,可以閱讀這篇文章《了解GitHub工作流》

在沒有測試的情況下,當你cv的時候,你需要将改動的代碼拉到你的裝置上,運作應用,然後手工測試代碼看看是否能正常運作。這很費時間,而且你也不會因為聽到說别人在cv一個PR的時候,略過了這個過程而感到驚訝。

而自動化測試會讓這個過程簡單得多。當你在項目中配置類自動化測試,你可以設定一個伺服器用來下載下傳待合并分支,執行測試套件,最後傳回一個是否通過測試的報告(圖1.1)。隻要你信任測試,那你就不再需要在自己的裝置上檢查代碼了。

第一章 介紹Vue應用的測試第一章 介紹Vue應用的測試

說明

許多開源項目要求開發者在添加新功能的時候加入新的測試,Vue項目隻接受那些包含為新代碼寫了測試的PR。

自動化測試除了使PR更容易評審之外,也是CI/CD(持續內建/持續傳遞)等現代工作流成為可能。你可以在[Martin Fowler的部落格](http:// mng.bz/nxVK)了解到它們。

目前為止我定義了自動化測試和手工測試,現在來講更細緻些,下一小節我會講些概覽,包含了自動化測試技術,以及你可以如何用它們去測試應用。

說明 就像the Facebook丢掉the變成Facebook一樣,現在也該丢掉自動化測試前面的自動化了。從現在起,我會将自動化測試簡稱為測試。

1.2 測試概述

目前位置,我講的測試還是在一個比較泛的層面。現在,我們來講講一些你能具體去寫的測試類型。在本書裡,你将會學到3種前端應用的測試類型——單元測試、快照測試和e2e測試。

1.2.1 e2e(end-to-end)測試概述

e2e測試是最直覺的測試類型。對于前端應用,e2e測試會自動運作浏覽器,從使用者角度來檢查應用是否正确運作。

想象一下你在寫一個電腦應用并且想測試它能否正确地将兩個數相加。你可以寫一個e2e測試來打開浏覽器,加載電腦應用,然後點選數組“1”按鈕,再點選“+”号,再點選“1”按鈕,點選“=”按鈕,最後檢查螢幕是否正确顯示結果“2”。你可以在下面的例子看到,如果是代碼實作會是什麼樣子。

表1.1 一個檢查電腦兩數之和的e2e測試

function testCalculator(browser) {
  browser
    .url('http://localhost:8080') // 打開在本地運作的應用
    .click('#button-1') // 點選電腦的按鈕
    .click('#button-plus')
    .click('#button-1')
    .click('#button-equal')
    .assert.containText('result', '2') // 斷言電腦正确顯示的結果
    .end();
}
           

e2e測試是個省時利器。在你寫完e2e測試後,你可以随心所欲地運作它,想象下有上百個這樣的測試套件能夠省下多少時間!

在一開始,e2e測試看起來像是唯一你需要的測試工具,但這裡有一點問題。首先,e2e測試非常慢,加載浏覽器需要花上幾秒,并且網站響應可能會比較慢。通常一個e2e測試套件運作需要花費30分鐘,而且如果你單純靠e2e測試,那你将會花上幾個小時運作測試套件。

e2e測試的另一個問題是,它的調試非常困難。如果你要調試e2e測試,,你需要打開浏覽器,然後自己模仿使用者操作來複現bug。在本地裝置運作e2e測試是很不好的,而且如果出現錯誤的是在你的持續內建伺服器而不是你本地裝置,此刻你将會很頭大。

說明

避免可重複性問題的一個辦法,就是在可重複的環境中運作e2e測試,比如docker容器中。docker容器已經超出了本書的範圍,但你應該考慮調查它們來運作e2e測試,以避免因為不同機器而導緻失敗的問題。

e2e測試還有一個問題,那就是它們有可能是不可靠的測試。不可靠的是指經常失敗的測試,盡管它們測試的應用是能夠正常工作的。也許是因為代碼運作太久了,也可能是API接口臨時壞掉了。它就像一個不靠譜的朋友,你将不再認真對待一個不靠譜的測試。“哎,測試又失敗了!讓我看看,噢,又是那個問題,它總是整天失敗,這個問題不用太擔心。”不靠譜的測試會令你的測試套件不好用,但當你編寫e2e測試的時候這是難以避免的。

如果你列一個程式員的吐槽榜,那我打賭e2e測試肯定會排在前三名。盡管它很有用,但不應該隻揪着它用。

在本書中,隻有一章專門講e2e測試,一方面是e2e測試的缺點,另一方面是因為e2e測試和架構無關的,不管你的應用是Vue或者MooTools寫的,它都能正常工作。

e2e測試自動化了你需要手動操作的部分,你可以設定它基于規律的間隔,在生産環境的網站上或者在合并代碼分支之前執行。

e2e測試不是給你一個新的測試方法,它隻是更快的手工測試。另一方面,單元測試提供了一個手工測試無法提供的新工具。

1.2.2 單元測試概述

單元測試是基于應用最小的部分(單元)運作測試的過程。一般來說,你測試的單元是函數,但是在Vue應用中,元件也是測試的單元(稍後會介紹)

還記得電腦應用嗎?在代碼中,應用通過sum函數來計算兩數之和。

如果你通過修改了代碼以提高可讀性,你可能還想測試一下函數是否可以正常運作。你可能會運作e2e測試,但是如果e2e測試失敗,你可能無法知道問題是否是因為

sun

函數,還是源代碼的其他部分。确定是否是

sum

函數出問題的唯一辦法就是獨立運作這個函數,你可以通過單元測試來實作。

單元測試是在獨立環境中的函數,調用你源碼中的函數并斷言它們的正确行為。看看下面這個簡單程式的代碼,這段代碼導入

sum

函數、運作并且在它的傳回值不是2時抛出異常。

表1.2 一個基礎的單元測試

// sum.js
export default function sum(a, b) { // 要被測試的函數
  return a + b;
}

// sum.spec.js
import sum from '../sum' // 将sum函數導入到測試檔案中

function testSum() {
  if(sum(1, 1) !== 2) {
    throw new Error('sum(1, 1) did not return 2') // 如果傳回值不是2,則抛出異常
  }
}

// 運作測試
testSum()
           

因為單元測試在獨立的環境中運作,是以當一個寫得好的單元測試失敗,它會像一個閃爍的霓虹燈一樣,指向出現問題的代碼。

不像e2e測試,單元測試運作得很快。它們運作隻要幾秒鐘,是以你可以在你每次修改代碼的時候,運作單元測試快速獲得回報,來确認這些修改是否會影響到代碼現有的功能。

單元測試令人滿意的一個點是它提供了說明,如果一個新的開發者剛接觸項目,并且想知道一個單元的行為,他們可以通過看單元測試來了解一個單元預期的行為是怎樣的。

我前面說過e2e測試的不可靠,測試會定期失敗盡管應用是正确工作的。寫得好的單元測試不會出現這種問題。隻要單元測試是确定的,你可以運作它上千次,而且它每次都能通過。

目前為止,我隻講了單元測試的好處,簡直讓人臉紅。但是我不相誤導你,像e2e測試和單元測試都有它們自己的問題。

單元測試的一個大問題就是它讓代碼難以重構,人們不經常講這個問題,但是我經常遇到這個問題。

定義

重構一般就是為了提高代碼品質,重新實作代碼的過程(但這取決于是誰來重構代碼)。

如果你有一個帶有單元測試的複雜函數,并且決定将它分成兩個獨立的函數,你需要将代碼對應的單元測試也做修改。這會讓人不願意去重構,有時候我不想去修改代碼結構就是因為有太多額外的單元測試代碼需要更新。這沒有簡答的解決方案,你在判斷寫測試代碼長期來看能否能夠節省時間時,這是需要額外考慮的點。

單元測試的另一個問題是它們隻檢查應用某個獨立的部分。你可以檢查一輛車每個單獨的部分都能正常運作,但是如果你沒有檢查它們合并起來的運作狀态以及引擎沒有點火,你的測試是沒有用的。單元測試就有這個問題,它們保證了代碼的單元能如預期,但是它們沒有測試單元間的工作是正确。這就是為什麼需要用e2e測試來補充單元測試。

到現在,我向你介紹了e2e測試和單元測試,最後一個你會從本書中學到的測試就是快照測試。

1.2.3 快照測試(Snapshot testing)

你玩過“大家來找茬”嗎?“大家來找茬”是一款遊戲,它提供2張看起來一樣但是有細微不同的圖檔,目标就是找到圖檔中不同的地方。

快照測試和”大家來找茬“有點相似,它會在你運作的程式中拍下快照圖檔并和之前保留的圖檔做比對。如果它們不一樣,那快照測試就失敗了。這中測試是一個很有用的方法來確定代碼在修改後還能正确渲染。

傳統的快照測試會在浏覽器中加載應用,并給渲染的頁面拍下快照。它們會将新拍下的圖檔和已經儲存的圖檔做對比,如果存在不同那就會顯示一個錯誤。這類快照測試存在一個問題,那就是不同的作業系統或者浏覽器版本會導緻測試失敗,盡管快照壓根就沒有變化。

在本書中,我會教你怎麼用Jest測試架構寫快照測試。Jest快照測試可以比較JavaScript中任何序列化的值來代替對比快照。你可以使用他們來比較從Vue元件中輸出的DOM。在第12章,你可以學習到快照測試的細節。

定義

序列化指的是,任何代碼可以被轉化為字元,然後再轉換回原來的值。實際上,它依賴于V8的方法,但是這裡不需要去深究裡面的細節!

現在你已經了解了每個你将要寫的測試類型。現在我們來看看如何通過組合不同的測試方式,來實作一個有用的測試套件(suit)。

1.2.4 有效組合測試方式

如果你将糖、面粉和奶油用正确的比例進行組合,你就能做出美味的曲奇面團。但是如果你弄錯了比例,你可能做出的是一團奶團。你需要通過正确的組合比例,對不同的測試套件進行組合,才能確定設計出的是高魯棒性(譯者注:就是高可靠性)的測試套件,而不是一堆亂七八糟的測試代碼。

如圖1.2,你可以看到前端測試金字塔。這表示了在你的前端代碼中,不同的測試方式的比例。

圖1.2 前端測試金字塔

第一章 介紹Vue應用的測試第一章 介紹Vue應用的測試

單元測試是金字塔最主要的組成部分——能在開發過程中提供快速的回報。快照測試運作起來也很快,而且它覆寫的範圍要比單元測試更大,是以你不需要像單元測試那樣多的快照測試。

正如前面所說,用e2e測試應用是很棒的,但是它很慢而且容易出奇怪的測試問題。是以避免奇怪測試問題的最好方法就是不寫它們,是以前端測試金字塔隻有一小部分的e2e測試。

非內建測試(No integration tests)

如果你是一名經驗豐富的開發者,你可能聽說過內建測試。內建測試是另一種測試的類型,通常是由單元測試和e2e測試組合而成。

但我并不推薦給前端代碼寫內建測試。內建測試在前端既難以定義,又難以編寫,還難以調試。

人們對內建測試有不同的定義,特别是在前端領域。有些認為運作在浏覽器中的測試就是內建測試;有些則認為隻要測試中,測試的單元依賴于一個子產品,就算內建測試。有些還認為,隻要是完全渲染一個子產品(fully rendered component)就算內建測試。

在第13章,為了確定後端服務能夠正确地傳回http請求,我将會教你如何實作一個服務端測試(我自己的定義的概念)。但是在這本前端測試的書中,你将不會寫任何關于內建測試的代碼。

在本書中,你将會建立一個測試套件,它的比例結構會和前端測試金字塔一緻。我将會教你如何編寫一個測試驅動開發工作流的測試套件。了解測試驅動開發的工作流是非常重要的,它将能讓你深刻了解本書中代碼結構是如何組織的。

1.2.5 測試驅動開發(TDD,Test-driven development)

測試驅動開發(TDD,Test-driven development)是一個工作流,指的是在寫源代碼(source code,譯者注:或者稱為業務代碼)前,先編寫失敗測試(failing test)的代碼。在寫一個元件代碼前,先寫測試代碼來確定元件行為正确。

一個流行的TDD方式是紅、綠、重構(譯者注:又稱”失敗-實作-通過“方式,靈活開發的一種方式)。紅、綠、重構是指:寫一個失敗測試(紅),讓測試通過(綠),最後重構代碼讓它更具有可讀性。

說明

我了解TDD不是适合每一個人,我也不打算向你推薦它。你不需要因為這本書就信仰TDD來獲得好處。我在這本書中使用TDD的主要原因是,它讓測試代碼先于源代碼,而本書的内容中,測試代碼是遠比源代碼重要的。

TDD有很多中口味——香草味、酸橙味、車厘子味、橙子味。我開玩笑的,當然,有很多中方式達成TDD。這本書使用一個關注前端版本的TDD。

一些TDD的擁趸在寫源代碼前,會寫完全部的測試代碼,但我不嚴格遵守TDD。我會在寫源代碼之前寫好單元測試,然後在源代碼完成後,再加入e2e測試和快照測試。我一般寫一個vue元件的流程是這樣的:

  1. 确定我要的元件
  2. 為每個元件編寫單元測試和源代碼
  3. 給元件編寫樣式
  4. 為完成了的元件添加快照測試
  5. 在浏覽器中手動測試下代碼
  6. 編寫e2e代碼

    在實際的生活中,有時候我并不會為元件編寫單元測試,有時候我又會在寫測試代碼前先寫元件代碼。TDD的擁趸聽到這可能會面露不悅,但是我發現死闆地套用TDD流程會讓開發速度變慢。

常言道,生活在于過程,而不在于目的地。盡管在一般的生活中這句話是真理,但是在開發應用的情況下就恰恰相反了。隻要你寫出的是有價值的、節省你時間的測試代碼,那怎麼寫出來就顯得不是那麼重要了。

我會在書中用大量篇幅告訴你去測試什麼,向你展示測試代碼,最後是還有那些讓測試能通過的源代碼。當你在給一個測試代碼加入源代碼之前,在運作測時預期測試将失敗。

到目前位為止,我告訴了你自動化測試的好處,但在你因為過于激動而去建一個什麼強化自動化測試(automated-test-appreciation)的社團之前,有一個免責聲明,那就是自動化測試不總是必須的。

1.2.6 學習什麼時候不測試

在我剛開始寫自動化測試的時候,我想要測試全部東西。因為我曾經一開始經受過沒有測試代碼的應用的痛苦,然後,就像一個宿醉的中年男人一樣,我下定決心不再這樣。但是我很快又學到一課,那就是測試降低開發速度。

當你在寫測試代碼的時候,時刻牢記你寫它們的原因是很重要的。通常來說,測試的目的是節省時間,如果你在工作的項目已經很穩定而且會長時間開發下去,測試代碼才會産生收益。

但當編寫和維護測試代碼所花的時間,比它們所節省下來的時間還要多,那你就壓根不應該寫這些測試代碼。當然,我們很難去知道在你寫測試代碼之前,确認到底你能省多少時間——随着時間推移,你才會了解到它。但是,例如,如果你在建立一個原型,為一個短期項目工作或者是為一個創業公司疊代想法,你幾乎不會從編寫測試代碼中獲益。

就算一個項目能從測試中獲益,它也很可能沒有你想象中那樣,需要那麼多的測試。讓我來告訴你你一個100%代碼覆寫率的誤區。

1.2.7 100%代碼覆寫率的誤區

代碼覆寫率是用來衡量你代碼庫中,有多少代碼已經運作過你自動化測試的代碼行數。通常代碼覆寫率通過百分比衡量:100%的代碼覆寫率意味着在運作測試中,每一行代碼都被執行了;0%意味着一行也沒有被執行到。這是一個有趣的名額,但是它會導緻一些可怕的後果。

測試提供的是邊際遞減的收益。它就像去健身房,當你第一次去健身房,你的肌肉增長會非常快。你隻要在幾個月内,每周去3個小時的健身房,就可以減掉你的啤酒肚并且看起來身材健美。但是随着你變得愈發強壯,你增肌的時間就越多。你在健身房花的時間越多,你從這些額外花費的時間所獲得的收益就越少。

這種規律在測試方面是一樣的。你能隻花一點時間,就寫出一個簡單的測試代碼來覆寫你應用中的核心功能。在你完成這些測試後,提升你代碼覆寫率就會愈發困難。如果你的目标是100%的代碼覆寫率(一些開發者的聖杯),那這就像想要從毛巾中擰幹最後的一滴水一樣難。

大部份時候,100%的代碼覆寫率不是目标所在。當然,如果你是在給一個支付應用的核心崗位上工作,一個bug可能會導緻百萬級别的損失,那100%的覆寫率對你是很有價值的。但在我的工作經驗中,大部份的應用并不會從100%的代碼覆寫率中受益。

在過去工作的幾年,我曾經在0%覆寫率、100%代碼覆寫率、以及介于兩者間覆寫率的項目工作過。0%代碼覆寫率是開發變得困難,但是100%代碼覆寫率會導緻開發效率降低并且比鼻涕蟲攀登一座沙丘還痛苦。

達到傳說中的100%代碼覆寫率不單單是十分好費時間的,而且就算到到100%代碼覆寫率,測試代碼也不一定能發現bug。有時候你可能會做出錯誤的假設,比如你測試的代碼調用了一個API,并且你假設它永遠不會傳回錯誤;當在生産環境中API真的傳回了一個錯誤,那你的應用就會崩潰。

你不會因為在每個應用中,努力達到100%的代碼覆寫率就成為測試高手。就像一個好的MMA運動員知道應該什麼時候從戰鬥中脫身,一個真正的測試高手知道什麼時候要寫測試,什麼時候不寫。

在下一章中,你将開始在“極客新聞”(Hacker News) APP上寫下你第一個單元測試。在此之前,我會給你“極客新聞”APP整體的概況以及這個應用的樣子。

1.3 編寫“極客新聞”APP

當我第一次接觸前端應用測試的時候,我讀的教程教給我的是如何為小型應用編寫測試代碼。它這樣對于單純學技術是有效的,但是對于我在真實世界中的大型應用測試中所遇到的問題,它并沒有提供答案,我隻能靠自己尋求答案。在這本書中,我想從頭到尾教你如何去測試一個應用,是以你将會為基于真實世界的“極客新聞”的克隆程式,編寫測試代碼。

“極客新聞”是一個社會新聞網站。它有動态的訂閱流,就像新聞故事、部落格文章和工作清單(圖1.3)。使用者可以給一條資訊投票加分或者減分。如果你用過Reddit,你對這個概念應該會很熟悉。

圖1.3 極客新聞應用

第一章 介紹Vue應用的測試第一章 介紹Vue應用的測試

說明

弄懂“極客新聞”最好的方式是你自己去通路它:https://news.ycombinator.com

在本書中,你不需要去實作一個投票系統,這的複雜度已經超出了Vue元件測試的範疇。你要做的是建立一個應用,它能顯示清單項、評論以及從“極客新聞”API中擷取的真實的使用者資料。

“極客新聞”的克隆程式将會使用Vue作為視圖部分,Vuex作為狀态管理部分,以及Vue-router作為用戶端路由。不用擔心你之前沒有使用過Vuex和Vue-router,我會在書的後面詳細講解他們。

用來教學如何測試Vue應用,“極客新聞”克隆程式是一個很好的應用。它既足夠複雜讓你能學到進階的測試技術,又簡單到能避免你陷入到設計的細節中。

現在你已經知道了将會學到什麼,差不多來談談Vue了。對于一本講測試Vue的書來說,我們已經離題很遠了

1.4 Vue測試概述

這是一本關于Vue測試的數,而非開發Vue應用的書。我不會從頭教你如何去使用Vue。如果你是一個對Vue完全0經驗的小白開發者,那應該從課外自學一下Vue的基礎知識,這樣你才能從本書中獲得最大的好處。

說明

如果要從零開始學Vue,我推薦由Erik

Hanchett和Benjamin Listwon寫的《Vue.js in action》這本書(Manning出版社, 2018年發行)。又或者,可以是我讀過的最好的文檔之一的Vue官方文檔。你可以在這裡檢視https://vuejs.org/v2/guide。

就是說,我将在貫穿全書中用來簡要解釋Vue特性或者連接配接資源,是給你需要時用來了解更多細節,并且書中有2章專門給你學習更複雜的主題Vuex和Vue-router。

盡管我不會教Vue.js 101(譯者注:這裡應該指的是Vue.js 101教程,可以點選連結檢視)。但我會在下一章之前教你一些基礎的概念,以便我們不會雞同鴨講。那我第一個要教你的術語就是Vue執行個體(Vue instance)

1.4.1 Vue執行個體

Vue應用是由Vue執行個體構成,每個應用最少有一個Vue執行個體。并且當你為元件編寫單元測試時,你将在測試中的元件建立一個vue執行個體。

在 表1.3 中,你可以看到一個Vue應用的簡單例子。要啟動應用,你需要使用options對象來建立一個新的Vue執行個體。Vue使用el選項來找到DOM節點,在其中渲染從模闆字元串的生成節點。

說明

我将會假定你熟悉DOM,如果你不熟悉DOM,你可以在MDN查到相關的介紹

表1.3 建立一個Vue執行個體

new Vue({
  el: '#app', // 選擇器用于從DOM中找到用來渲染的元素
  template: '<div>{{message}}</div>', // 模闆字元串用于生成DOM節點
  data() { // data在模闆字元串中使用
    return {
      message: 'hello Vue.js!'
    }
  }
})
           

生成DOM節點來床建立Vue執行個體就是衆所周知的挂載執行個體。如果你之前寫過Vue應用,那你将挂載一個Vue執行個體來啟動應用程式運作。

說明

如果你還對什麼是Vue執行個體感到困惑,你可以在Vue文檔中學習到它。

在 表1.3 的例子中,使用了模闆字元串,來描述Vue應該生成的DOM節點。你可以使用不同的方式來描述Vue應該渲染的DOM節點,現在我們來學習它。

1.4.2 模闆和渲染函數

Vue提供了聲明的方式來渲染DOM。換句話說,你描述Vue應該渲染的DOM節點。

你可以通過兩種方式描述DOM節點:模闆和渲染函數。模闆使用HTML文法來描述一個DOM,就像下面的代碼這樣:

表1.4 一個模闆字元

new Vue({
  // ..
  template: '<div>{{message}}</div>' // 渲染一個消息屬性的模闆字元串
  // ..
})
           

為了讓Vue從模闆中生成一個DOM節點,他需要将模闆轉換為渲染函數,稱為模闆編譯。而下面的表中,你可以在Vue的options中直接使用渲染函數代替使用模闆字元串。

表1.5 使用渲染函數

new Vue({
  // ..
  render(createElement) {
    return createElement('div), this.message
  }
})
           

Vue運作渲染函數來生成真實DOM的虛拟DOM(JavaScript代理),将在下面的代碼展示。然後它會比較虛拟DOM和真實DOM之間的差別,并且更新真實DOM來和虛拟DOM保持一緻。

表1.6 虛拟DOM例子

{
  tag: 'div',
  children: [
    {
      text: 'Hello Vue.js'
    }
  ]
}
           

說明

如果你想學習更多關于渲染函數或者虛拟DOM,你可以在Vue文檔中的http://mng.bz/dP7N和http://mng.bz/VqwP找到。

渲染函數的可讀性比模闆差。你在寫元件的時候應該盡可能使用模闆,但你應該在這麼做的時候意識到,Vue必須把模闆編譯到渲染函數中去。

模闆讓代碼變得易讀,但一個大模闆也會變得難懂。Vue由一個元件系統組成,是以你可以分割模闆成為易讀且好維護的獨立單元。本書的大部分是關于Vue元件的單元測試,是以你必須對什麼是Vue元件有深入的了解。

1.4.3 了解Vue元件系統

元件是你可以在Vue模闆中使用的獨立子產品代碼。他們抽象了邏輯,使模闆更易讀。如果你用過像React或則Angular之類的前端架構,你會對元件的概念感到熟悉。對于大型Vue應用,它自始至終都是元件。

解釋元件最簡單的方式就是讓你看看代碼。你可以看到在接下來的代碼示例中看到

<custom-title>

元件。請注意,在使用Vue注冊元件後,你就可以像用HTML标簽一樣在你的代碼中使用它。

表1.7 在Vue中全局注冊元件

JavaScript

Vue.component('Hello-vue', {
  template: '<div>Hello Vue.js</div>'
})
           

HTML

<div>
  <hello-vue />
</div>
           

你可以通過一些不同的方式來定義元件,但在這本書裡,我将會讓你寫單檔案元件(single-file components, SFCs。譯者注:後面将簡稱為SFC)。

說明

這本書中所有的技術,對于任意通過正确方式定義的Vue元件,都會以相同的方式工作。

Vue的SFC可以通過它們的

.vue

拓展符号辨別。SFC可以包含一個

<template>塊

(和模闆字元串一樣)、一個

<script>

塊、一個

<style>

塊以及自定義塊(表 1.8)。

說明

在本書中,你不應該使用任何自定義塊,但你可以在vue-loader文檔中學習到它們。

<script>

塊中導出的對象,被稱為元件選項對象(component options object),它包含了許多Vue根執行個體可以使用的選項。

表1.8 單檔案元件(SFC)

<!-- template塊 -->
<template>
  <div>{{message}}</div>
</template>

<!-- script塊 -->
<script>
  export default { // 元件選項對象
    data: {
      message: 'Hello Vue.js!'
    }
  }
</script>

<!-- style塊 -->
<style>
  div {
    color: red;
  }
</style>
           

SFC不是合法的JS或HTML,你不能直接在浏覽器中運作他們,是以你需要在你發送他們到用戶端之前編譯他們。

一個編過的SFC,會變成一個JavaScript對象,它帶有模闆轉換而成渲染函數。你可以在下面看到例子。

表1.9 編譯過的SFC

Module.exports = default {
  render() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm.self._c || _h;
    return _c('p', [_vm._v("I'm a template")])
  },
  name: 'example-template'
}
           

我希望這段代碼沒有吓到你,實際上,編譯過的SFC并不是設計給人們閱讀的。你不需要因為編譯過的渲染函數就焦慮,使用渲染函數是Vue架構的工作。這裡的要點是SFC被編譯成一個帶有渲染函數的對象。

這讓你很好地了解應該測試的元件的哪一部分。

1.4.4 單元測試元件

決定編寫哪些單元測試是很重要的,如果你為元件的每個屬性都編寫測試,那你的開發将會很慢,并且建立了一個低效的測試套件。

一種決定元件哪部分應該被測試的方法,是使用*元件契約(component contract)*的概念。元件契約是目前元件和應用其他元件之間的約定。

當你開始一份新工作的時候,你會和你的雇主簽訂一份契約。你同意你每周将會花40小時的時間在工作上,以換取工資。因為你已經在契約中同意了工作40小時,你的雇主也能放心地假設,隻要他們支付你工資,他們就能讓你每周工作40小時。

同理,當你寫了一個元件被用作應用的一部分,你會定義一個元件行為的約定,其他元件會完全假設這個元件會完全按照約定,并且隻要提供正确的入參就會産出約定的輸出。

輸入和輸出的概念在元件契約中很重要。一個好的元件單元測試應該總是由一個輸入觸發,并且斷言元件有正确的輸出(圖1.4)。你應該從一個不清楚元件如何實作的,但使用這個元件的開發者角度來編寫測試。

第一章 介紹Vue應用的測試第一章 介紹Vue應用的測試

元件常見的輸入就是使用者動作,比如當使用者點選一個按鈕;最常見的輸出就是渲染函數生成DOM節點。但Vue元件中還存在很多種的輸入輸出,例如,輸入可以是:

  • 元件props屬性
  • 使用者動作(比如按鈕點選)
  • Vue事件
  • Vuex儲存的資料

Vue元件的輸出可以是:

  • 分發事件(emitted events)
  • 外部函數調用

說明

不要擔心你不懂分發事件和Vuex存儲資料是什麼。你将會在本書後面學習到他們。

想象一下,你有一個授權狀态的元件,它接收一個

authorized

的prop。如果

authorized

true

,它将在

<div>

元素中渲染“你已被授權”,如果

authorized

false

,它将在

<div>

元素中渲染“你未被授權”。

定義

prop

是傳遞給元件的一段資料。

prop

是一個父元件到子元件傳遞資料的方式。你可以在Vue文檔中學習更多關于它的知識。

你可以在下面看到AuthorizedMessage元件。

表1.10 AuthorizedMessage.vue

<template>
  <div>
    <!-- 條件渲染文本 -->
    {{ authorized ? '你已被授權' : '你未被授權' }} 
  </div>
</template>

<script>
  export default = {
    name: 'loader',
    props: ['authorized'] // prop聲明
  }
</script>
           

如果你在一個應用中使用了這個元件,你會希望當你給prop

authorized

指派為

true

的時候,它顯示“你已被授權”;當你給prop

authorized

指派為

false

的時候,它顯示“你未被授權”。這是它的元件契約,也是你應該為之寫單元測試的功能。在本書裡,我将會使用元件契約的概念來告訴你,應該為元件寫什麼測試。

現在你已經對測試有了全面的概覽,你将會通過自己成為一名測試高手。在下一章,你将會建立一個測試腳本并且寫下你第一個單元測試。

總結

  • 有兩種類型的測試,自動化測試和手工測試。
  • “前端測試金字塔”測試套件有單元測試、快照測試和e2e測試。
  • 測試不總是有收益的,如果測試不能為你節省時間,那你就不應該寫它。
  • Vue應用由Vue執行個體組成,Vue執行個體使用模闆字元串或則渲染函數來描述DOM。
  • SFC(single-file component)會被編譯成帶有渲染函數的對象。
  • 你可以使用元件契約來定義要為Vue元件寫什麼單元測試。