原文:testing your frontend code: part ii (unit testing)我們在part1裡已經說過,但與那測試就是測試單元的**,不管這些單元是函式、模組還是類。多數人認為測試應該以單測為主,但我不這麼認為,如果你同意也沒有問題。我會一遍一遍又一遍地在這一系列文章中強調,你怎測試都行,只要你寫了足夠多的測試,讓你對你的上線有信心就行。by gil tayar
不管你寫多少單測,單測確實是最好寫也最好懂的測試,它們天生具有函式屬性。設定乙個單元的輸入,執行,檢查輸出(輸入可能就是乙個函式的引數,輸出就是返回值)。
更重要的是你應該提醒自己寫**時要讓這些單元彼此隔離,不會相互依賴,這樣才能方便單測。
理論已經夠多了,我們看下我們的計算器,原始碼在這裡。這是個react應用,有兩個主要的元件,keypad
和display
。顯然他們是單元且對其他單元無依賴。但是他們是react層面的單元,以後我會專門講如何測它們。
如果你已經閱讀過**可能會疑問為啥我不用jsx。原因是我不想使用**轉譯。node和現代的瀏覽器能夠識別es6,所以為啥不讓你寫的**直接執行呢?是的,我的**不能再ie中執行,但是這只是個demo,所以沒問題。在乙個真實的專案裡,我會新增**轉譯的。負責計算的邏輯並不在元件中,它是乙個單獨的模組譯註:最新的**倉庫已經用jsx重構並增加了babel轉譯,所以這段呵呵了。
calculator
,並不依賴react。這樣的模組是最適合單測的。對ui和io沒有依賴的模組最適合單測。你應該盡力讓你更多的業務邏輯以不依賴io或者ui的形式寫成模組。
在前端裡,不依賴io是啥意思呢?不訪問檔案、資料庫… ?不,前端裡本來就沒有這些。但是還會有ajax,local storage,dom 訪問,瀏覽器api訪問,對我而言,這些都是io。
我是如何把計算器的邏輯和元件分開的?在這裡,其實很簡單,這些邏輯都是演算法類的,我把它們放到了calculator
模組中。
這個模組非常簡單,輸入是計算器的當前狀態(乙個物件)和乙個字元(乙個數字或者運算子),返回值是計算器的新狀態。如果你用過redux,這個邏輯跟redux的reducer差不多。但是如何獲取最原始的狀態呢?簡單,這個模組同樣export了initialstate
,你可以用它去初始化計算器。計算器的狀態並非不透明的,它包含可乙個元件display
,用來將計算器的內在狀態顯示出來。
如果你沒有耐心去仔細閱讀**,我們這裡只看下開頭就行,這部分最重要,演算法是怎麼實現的其實無關緊要。
module.exports.initialstate =
module.exports.nextstate = (calculatorstate, character) => else
if (isoperator(character)) else
if (isequalsign(character)) else
}//....
複製**
怎麼測試呢?我們通常會用乙個測試框架。當下最流行的測試框架是mocha,我們就用它來測試。當然用jest,jasmine,tape或者其他框架都可以。
所有的測試框架都是類似的——你把測試**寫成函式,測試框架負責執行它們。
當npm install
moch後,我們就可以通過npm指令碼執行了。當然,命令就是"mocha"。看下package.json
,你會看到:
"scripts": ,
複製**
執行npm test
,就會執行以test
打頭的資料夾裡的測試指令碼。如果你clone了這個**倉庫,你要先npm install
。
(順便說下,把測試指令碼放在根目錄下的test
資料夾中是測試的慣例,如果你想要讓別人認為你寫測試很專業,那你也應該這麼做)
執行後,輸出長這個樣子。
如果有乙個測試沒有通過,你會看到刺眼的紅色,然後就可以馬上修改了。
看一下我們的測試用例:
// test-calculator.js
const = require('mocha')
const = require('chai')
const calculator = require('../../lib/calculator')
describe('calculator', function () )
it('should replace 0 in initialstate', () => )
//...
複製**
我們先引入mocha
,還有它的斷言庫expect
(稍後我們會將啥事斷言庫)。引入一些我們需要的函式describe
、it
。
然後引入我們要測試的模組——calculator
。
然後就是使用it
函式定義的測試用例了,如下:
it('should show initial display correctly', () => )
複製**
it
函式接受乙個字串引數,用來描述測試用例,另乙個引數是乙個函式,就是測試本身了。但是it
是不能「裸奔」的,需要被包裹在describe
函式定義的測試組中。
在測試邏輯中寫啥呢?其實啥都可以。在這裡我們就是判斷了下初始展示的值是不是等於0. 如果不用expect
,我們可以這麼寫:
if (calculator.initialstate.display !== '0')
throw
'failed'
複製**
mocha中如果乙個測試不通過,就會丟擲乙個異常,就是這麼簡單。但是使用expect
讓我們可以使用他的一些特性來方便地檢查陣列、物件的值。
這就是單元測試的主旨了——執行乙個或者一組函式(如果你是物件導向測試,則通常例項化乙個物件,然後呼叫它的方法),檢查返回的結果是否等於預期結果。
注意到很重要的一點——單測是執行在node環境下的。即使計算器應用的**是跑在瀏覽器中,我們仍然使用node去跑我們的測試,包括要上線的**。
這怎麼能行呢?這是因為我們的**是同構的。這意味著它們能同時執行在瀏覽器和node環境中。如果你的**中沒有任何io操作,這就意味著它並不是只能在瀏覽器中執行。尤其是,我們的**使用了require
來組織**,既能被nodejs識別,又能被webpack打包(看下package.json
,你就會發現使用了webpack)。
"scripts":
複製**
順便提一下,我們可以使用karma來實現在瀏覽器中執行mocha。但是我謹認為如果能在node中執行就在node中執行(現在你其實很容易寫出在兩端都能執行的**),因為無論是執行還是debug都更方便。不編譯**的話,執行起來會更快。
但是不在瀏覽器中跑測試,我們就不能確認我們的**能在瀏覽器中執行。兩個環境中的一些細微差別可能會導致一些問題。
上面說的問題就是e2e測試要管的事了——在真實的瀏覽器環境中測試我們的**。下週我們將如何寫e2e測試。
前端測試 Part II (單元測試)
原文 testing your frontend code part ii unit testing by gil tayar 我們在part1裡已經說過,但與那測試就是測試單元的 不管這些單元是函式 模組還是類。多數人認為測試應該以單測為主,但我不這麼認為,如果你同意也沒有問題。我會一遍一遍又一遍...
前端測試 Part II (單元測試)
我們在part1裡已經說過,但與那測試就是測試單元的 不管這些單元是函式 模組還是類。多數人認為測試應該以單測為主,但我不這麼認為,如果你同意也沒有問題。我會一遍一遍又一遍地在這一系列文章中強調,你怎測試都行,只要你寫了足夠多的測試,讓你對你的上線有信心就行。不管你寫多少單測,單測確實是最好寫也最好...
單元測試 單元測試文章收藏
前言 前段時間公司計畫做自動化測試,自己也打算圍繞幾個點做相關調研,現在想想呢?其實對自動化測試的概念都還不是十分清晰,當時主要還是圍繞 單元測試 向qa小夥伴學習了一段時間,現由於公司重組,學習中斷,這裡簡單記錄一些單元測試好文,留待後續參考.什麼叫自動化測試?自動化測試覆蓋率?覆蓋率如何做到的?...