做爲一個前端開發到底要不要寫測試?來看看《前端要寫單元測試?不存在的!那e2e呢?》

故事背景

Up所在的開發團隊,因爲測試人員(如下簡稱QA)的資源匱乏,較難保出品質量,窮則思變,近年來Up嘗試和實踐了前端的各種測試方法,今天寫出來與你們分享,討論前端

前端測試的種類

簡單過一下目前前端測試的種類,這不是重點,瞭解的同窗能夠跳過不看 java

網上介紹各種前端測試的文章很多,光SF就有很多好文,我大體歸類了一下,主要分爲2類react

1. 前端單元測試  (Unit Test如下簡稱 - UT)
 2. 前端e2e測試

第1點單元測試,你們應該不陌生,就算你沒寫過前端的UT,那你確定也聽過什麼mocha,jasmine,jest這類測試框架,UT的意義在於比較細粒度的去測試咱們業務代碼中寫的function,測試function裏提供的method是否可靠。git

就比如造房子的時候咱們對每塊磚的密度,重量,長寬高是否符合規範等數據進行測試,以確保每塊磚都是ok的,不會出現空心磚等狀況,從而保證最後造出來的房子沒有安全隱患

第2點e2e測試
e2e測試就是端對端測試,簡而言之,就是利用一些工具庫提供的API使用代碼來模擬終端用戶在UI界面上的操做,好比輸入,點擊等等。目前經常使用的工具備,selenium, puppeteer,phantom,protractor(angular), Nightwatch(Vue)等等github

重點來了!個人團隊到底需不要前端開發寫測試?

根據上一段的內容,咱們分爲2塊來討論web

需不須要寫「單元測試」?

上一段舉了一個磚頭與房子的例子來簡單闡述了單元測試的重要性,可是這也偏偏說明了另一個問題,也就是越是基礎的,底層的代碼越是須要進行完備的單元測試,以保證它是可靠的,從而保證依賴它的其它模塊不會受到影響。先後端分離流行後,前端開發從系統架構層面來看,實際上已是站在食物鏈頂端的男人。後端

第一個金字塔模型

clipboard.png

從這個模型能夠看出,前端做爲消費者是站在最頂層的,它是Service層的消費者,因此只有保證Service層是健壯可靠,才能保證UI層的可靠。可是前端並不被其它層所依賴,由於它已經站在了頂點。因此除了最終用戶我並不須要對其它層面負責,不用負責我憑什麼還要寫UT? 持不一樣意見的同窗,稍安勿躁,咱們繼續深刻分析api

第二個金字塔模型

clipboard.png

前端也有本身的金字塔模型,咱們在寫UI的時候也會對底層代碼有依賴,好比引入了mvvm framework, 要使用lodash之類的util庫,要用到公共組件,固然咱們能夠本身實現這些前端較爲底層的庫,組件,可是絕大部分場景下,都是拿來主義,從github上找一個星星多的,而且默認認爲這些開源庫都已經作了充分的UT,是可靠的。而咱們90%的精力都花在了更上層更頂端的業務代碼上,咱們依舊是站在食物鏈頂端的頂端,地位無可撼動,得出的結論是依舊不須要寫UT安全

哪些狀況下你可能須要寫前端UT? 來作一組判斷題

1. 你寫的是個util類,是會被其餘類調用的那種?
2. 你寫的是一個公共component,是會被其餘工程調用的那種?
3. 你寫的是一個開源項目

若是以上3個問題有一個確定回答,你都應該考慮寫UT了。因此說,UT對於前端來說,重不重要?重要!要不要寫?看狀況前端框架

需不須要寫E2E測試?

看了上面的結論,嚴謹的同窗可能已經要跳起來了,指着Up的鼻子說:「啊!誰說那90%的業務代碼不被依賴的,咱們並無站在最頂端,咱們上面還有客戶還有上帝,這業務代碼是要對客戶負責的,因此咱們仍是要爲這業務代碼的健壯可靠性寫UT」

能質疑這個問題的同窗,很是好,很是秀,你的出發點是很好的,可是咱們不妨換個角度來思考一下這個問題。首先,單元測試的存在有個前提,就是提供者和它上層的消費者須要在同一個特定的消費體系裏,只有在同一個體系裏,對提供者寫UT纔有意義,不然這是不牢靠的。要證實這一點很容易,好比我java寫的一個util類,我確定會在java這個特定的消費環境裏來對這個util進行UT,由於它的上層消費者確定也是java環境。一個前端的mvvm framework的UT確定是基於JavaScript環境來寫的,而不多是別的語言,由於消費你的上層建築也是基於JavaScript來調用的,固然有人說提供restful api的service層,雖然跟語言環境無關,但它都是基於http這個特定的消費環境的,或者也能夠說接口層面的test已經屬於整合測試的範疇。

可是,前端的業務代碼卻和上層的消費者——用戶,不在同一個特定環境裏,是脫節的,展示在用戶面前的是GUI,用戶經過一系列的用戶事件,點擊,輸入,拖動,肉眼觀測實現頂層消費。而不是呼出F12,在console裏把前端的業務代碼把調用一遍。因此說即便你的前端業務代碼的UT作得再棒,理論上來講也是不可靠的。

那麼,既然如此,如何保證業務代碼是可靠的,能對消費者——用戶負責呢?
說了這麼多,終於引出了本文的重點——e2e自動化測試(如下簡稱Automation Test——AT),我可使用各種e2e工具,模擬用戶的操做行爲來進行最終的驗收測試,這樣我不就跟用戶是在同一個體系裏了麼?!且慢,一樣先根據你項目的實際狀況作幾道是非題

1.測試團隊是否兵強馬壯  (基於人海戰術的人肉e2e測試)
2.產品UI是否相對不穩定,常常大改 (改e2e case都來不及)
3.測試團隊是否已經熟練掌握自動化測試技術,並已經運用起來  (QA來寫e2e自動測試,理想國,前端就能夠甩手了)
4.每個迭代週期,留給QA測試時間是否充裕  (人肉e2e測試時間充足)
5.Service接口的測試覆蓋率是否很高,後端UT的覆蓋率是否很高 (底層建築穩,隱患少)
6.每個迭代週期,留給前端開發的時間是否很緊張 (前端寫完業務代碼,也要有時間寫e2e代碼)

若是你的答案裏有2個以上的yes,可能e2e AT並非現階段必需要引入的,由於你背後有足夠強大的測試團隊支撐或者充裕的時間來保證產品被交付給用戶前有足夠的可靠性,或者是因爲產品的特殊性,已經項目時間安排的不合理致使沒法實施e2e AT

第三個金字塔模型

clipboard.png
e2e測試(無論是人肉的也好,自動化的也好)e2e測試在整個系統測試的貫通性覆蓋率上來講是最大的,它能夠覆蓋從地基到頂端的這一長串的範圍。因此若是說UT是用來保證保證成品各個層級可靠性的話,那e2e就是用來驗證這種可靠性的,而且它的做用範圍運不止此。

引入e2e AT

團隊中,若是QA資源匱乏,且UI變化的頻率不是很頻繁的狀況下,爲了提升工做效率,提高產品質量了,咱們就要考慮引入是該引入e2e自動化測試了來替代一部分的QA人肉工做量。誰來寫e2e測試? 第一順位繼承人,前端當仁不讓!

理由有3

1. 前端須要對本身寫的業務代碼負責,寫UT又不可靠,那就只有寫基與功能模塊的AT了
2. 模擬用戶操做,AT須要對各個DOM節點進行操做,前端對這個再熟悉不過
3. 有數款基於JavaScript的AT工具,學習成本低

e2e AT框架的選擇

Selenium
目前市面上AT工具琳琅滿目,種類繁多,up目前使用的是selenium + jest, selenium通常來講是雷打不動的,雖然咱們主要使用的是它的webdriver功能,選擇此類驅動型工具,up有個建議就是不要選擇針對某種前端框架自帶的自動化工具,諸如之前angular1時代up用過的protractor,它的寫法對UI框架是強耦合的,且封裝的API並不比比較原生的selenium高明多少,如若他日項目技術升級爲Vue或者React以前寫的AT case基本就廢了,因此仍是選用比較common的AT工具會比較好。

Jest
以前,up用的是mocha,jest雖然是爲react量身打造,可是把它當成一個common的測試框架也挺好用,它有個比較有用的功能就是快照snapshot,爲何說快照很好用,是由於,親手寫過AT的朋友大多有些體會就是——AT寫操做容易作判斷卻難,有了快照以後,就能夠用2張快照進行比較,從而大大節省了取dom節點的text的代碼,直接兩張圖一對比就玩事兒了。固然jest的快照功能你要本身實現也很方便,若想要保持現有的mocha或者jasmine同樣能夠引入快照功能。

一個e2e AT case的測試範圍

根據Up的經驗,我認爲一個e2e case的範圍最好以一個功能模塊爲最小單位,好比用戶管理,一個case裏我須要覆蓋到:建立用戶,查詢用戶,編輯用戶,刪除用戶等4個基本操做。

//user.e2e.spec.js
const UserModule = require('UserModule');
const AuthModule = require('AuhtModule');
let userModule;
const userName = 'at_test_user';

beforeAll( ()=>{
    new AuthModule().login();
    userModule = new UserModule();
})

test('user:' + userName +'should not be exited', ()=> {
    userModule.find(userName);
    const image = webdriver.takeSnapshot();
    expect(image).toMatchSnapshot();
})

test('user:' + userName +'should be created successfully', ()=> {
    userModule.create(userName,pwd);
    const image = webdriver.takeSnapshot();
    expect(image).toMatchSnapshot();
})

//... other cases....

afterAll(()=>{
    webdriver.quit();
})

爲何不直接在spec裏使用webdriver操做dom?

建議你們都給測試的功能對象封裝一個類,好比上面僞代碼裏的UserModule

//UserModule.js
module.exports = function UserModule(){

    this.find = function(username){
        //...
        webdriver.findElement(xxxx).click();
    }
    this.create = function(user,pwd){
        //...
         webdriver.findElement(xxxx).input(xxxx);
        //...
        webdriver.findElement(xxxx).click();
    }
    // other operations

若是往後寫其餘case依賴於User的數據,那麼就在before之類的地方進行userModule的調用來簡歷基礎數據。這裏不贅述了,OO的東西你們掌握的都比我好。

e2e AT的覆蓋率

在人員有限的狀況下,什麼case須要些AT,那些不須要,或者不急着寫,能夠往後慢慢補

1. 新功能不須要急着寫AT,應該交給QA人肉測試,待功能上線後再慢慢補齊
2. 反28原則: 28原則是指最重要的只佔其中一小部分,約20%,其他80%儘管是多數卻不重要,可是寫AT須要反過來,咱們優先寫那80%不經常使用到的功能,至於那重要的20%,因爲常常被使用,它能不能工做一目瞭然,其實也是最健壯的,須要寫AT來覆蓋的優先級就不顯得這麼高了,反而那不經常使用的80%功能每每沒有通過大量的用戶測試,很容易在某次迭代中產生新的bug。
3. 優先寫happy path,優先保證一個功能模塊的主線暢通,再寫邊界值測試。

e2e AT的重要性

先說說Regression Test即迴歸測試,當有新功能上線後,咱們須要對產品老的功能進行迴歸測試,以確保新代碼的加入沒有引入新的bug。一般一次迭代中,QA會花費大約20~30%的時間進行迴歸測試,可見迴歸測試的重要性,可是不少狀況下,因爲項目時間緊迫,或者緊急發佈等狀況,被壓縮和犧牲的每每是迴歸測試,而e2e AT正好能夠覆蓋一部分的迴歸測試,若是你的AT case覆蓋率越高,則迴歸測試的覆蓋率也越高,出品也就越穩定,若是AT能覆蓋絕大部分的迴歸測試,而AT的執行效率又是人肉執行的數倍,那QA的工做量就被大大的下降。

e2e AT在開發流程中的位置(什麼時候觸發AT)

當新的代碼合併到主線並部署到測試環境後,進入QA人肉測試環節前,是觸發AT的最佳時機。bug是越早發現越好,AT與jenkins等CI工具能夠很好的整合,也不依賴於什麼特殊插件,跑完AT後自動生成report,如有失敗則發送郵箱第一時間暴露問題,豈不美哉

幾句話總結

關於前端UT:業務代碼能夠不寫UT關於前端e2e: 推薦用e2e AT來覆蓋前端的業務代碼,並歸入開發流程另外,歡迎有持不一樣意見的同窗參與討論! 若是你有好的建議歡迎留言,畢竟是我一家之言,期待能碰撞出技術火花

相關文章
相關標籤/搜索