當前位置:
首頁 > 知識 > Web 前端單元測試到底要怎麼寫?

Web 前端單元測試到底要怎麼寫?

隨著 Web 應用的複雜程度越來越高,很多公司越來越重視前端單元測試。我們看到的大多數教程都會講單元測試的重要性、一些有代表性的測試框架 api 怎麼使用,但在實際項目中單元測試要怎麼下手?測試用例應該包含哪些具體內容呢?

本文從一個真實的應用場景出發,從設計模式、代碼結構來分析單元測試應該包含哪些內容,具體測試用例怎麼寫,希望看到的童鞋都能有所收穫。


項目用到的技術框架

該項目採用 技術棧,用到的主要框架包括: 、 、 、 、 、 、 、 。


應用場景介紹

這個應用場景從 UI 層來講主要由兩個部分組成:

工具欄,包含刷新按鈕、關鍵字搜索框

表格展示,採用分頁的形式瀏覽

看到這裡有的童鞋可能會說:切!這麼簡單的界面和業務邏輯,還是真實場景嗎,還需要寫神馬單元測試嗎?

別急,為了保證文章的閱讀體驗和長度適中,能講清楚問題的簡潔場景就是好場景不是嗎?慢慢往下看。


設計模式與結構分析

在這個場景設計開發中,我們嚴格遵守 單向數據流 與 的最佳實踐,並採用 來處理業務流, 來處理狀態緩存,通過 來調用後台介面,與真實的項目沒有差異。

分層設計與代碼組織如下所示:

中間 中的內容都是 相關的,看名稱應該都能知道意思了。

具體的代碼請看 這裡。


單元測試部分介紹

先講一下用到了哪些測試框架和工具,主要內容包括:

,測試框架

,專測 react ui 層

,具有獨立的 fakes、spies、stubs、mocks 功能庫

,模擬 HTTP Server

如果有童鞋對上面這些使用和配置不熟的話,直接看官方文檔吧,比任何教程都寫的好。

接下來,我們就開始編寫具體的測試用例代碼了,下面會針對每個層面給出代碼片段和解析。那麼我們先從 開始吧。

為使文章盡量簡短、清晰,下面的代碼片段不是每個文件的完整內容,完整內容在這裡。


actions

業務裡面我使用了 來產生 ,這裡用工具欄做示例,先看一段業務代碼:

對於 測試,我們主要是驗證產生的 對象是否正確:

這個測試用例的邏輯很簡單,首先構建一個我們期望的結果,然後調用業務代碼,最後驗證業務代碼的運行結果與期望是否一致。這就是寫測試用例的基本套路。

我們在寫測試用例時盡量保持用例的單一職責,不要覆蓋太多不同的業務範圍。測試用例數量可以有很多個,但每個都不應該很複雜。


reducers

接著是 ,依然採用 的 來編寫 ,這裡用表格的來做示例:

這裡的狀態對象使用了

對於 ,我們主要測試兩個方面:

對於未知的 ,是否能返回當前狀態。

對於每個業務 type ,是否都返回了經過正確處理的狀態。

下面是針對以上兩點的測試代碼:

這裡的測試用例邏輯也很簡單,依然是上面斷言期望結果的套路。下面是 selectors 的部分。


selectors

的作用是獲取對應業務的狀態,這裡使用了 來做緩存,防止 未改變的情況下重新計算,先看一下表格的 selector 代碼:

這裡的分頁器部分參數在項目中是統一設置,所以 reselect 很好的完成了這個工作:如果業務狀態不變,直接返回上次的緩存。分頁器默認設置如下:

那麼我們的測試也主要是兩個方面:

對於業務 selector ,是否返回了正確的內容。

緩存功能是否正常。

測試代碼如下:

測試用例依然很簡單有木有?保持這個節奏就對了。下面來講下稍微有點複雜的地方,sagas 部分。


sagas

這裡我用了 處理業務流,這裡具體也就是非同步調用 api 請求數據,處理成功結果和錯誤結果等。

可能有的童鞋覺得搞這麼複雜幹嘛,非同步請求用個 不就完事了嗎?別急,耐心看完你就明白了。

這裡有必要大概介紹下 的工作方式。saga 是一種 的生成器函數 - Generator ,我們利用他來產生各種聲明式的 ,由 引擎來消化處理,推動業務進行。

這裡我們來看看獲取表格數據的業務代碼:

不熟悉 的童鞋也不要太在意代碼的具體寫法,看注釋應該能了解這個業務的具體步驟:

從對應的 里取到調用 api 時需要的參數部分(搜索關鍵字、分頁),這裡調用了剛才的 selector。

組合好參數並調用對應的 api 層。

如果正常返回結果,則發送成功 action 通知 reducer 更新狀態。

如果錯誤返回,則發送錯誤 action 通知 reducer。

那麼具體的測試用例應該怎麼寫呢?我們都知道這種業務代碼涉及到了 api 或其他層的調用,如果要寫單元測試必須做一些 mock 之類來防止真正調用 api 層,下面我們來看一下 怎麼針對這個 saga 來寫測試用例:

這個測試用例相比前面的複雜了一些,我們先來說下測試 saga 的原理。前面說過 saga 實際上是返回各種聲明式的 ,然後由引擎來真正執行。所以我們測試的目的就是要看 的產生是否符合預期。那麼 到底是個神馬東西呢?其實就是字面量對象!

我們可以用在業務代碼同樣的方式來產生這些字面量對象,對於字面量對象的斷言就非常簡單了,並且沒有直接調用 api 層,就用不著做 mock 咯!這個測試用例的步驟就是利用生成器函數一步步的產生下一個 ,然後斷言比較。

從上面的注釋 3、4 可以看到, 還提供了一些輔助函數來方便的處理分支斷點。

這也是我選擇 的原因:強大並且利於測試。


api 和 fetch 工具庫

接下來就是api 層相關的了。前面講過調用後台請求是用的 ,我封裝了兩個方法來簡化調用和結果處理: 、 ,分別對應 GET 、POST 請求。先來看看 api 層代碼:

業務代碼很簡單,那麼測試用例也很簡單:

由於 api 層直接調用了工具庫,所以這裡用 來替換工具庫達到測試目的。

接著就是測試自己封裝的 fetch 工具庫了,這裡 fetch 我是用的 ,所以選擇了 來模擬 Server 進行測試,主要是測試正常訪問返回結果和模擬伺服器異常等,示例片段如下:

基本也沒什麼複雜的,主要注意 fetch 是 promise 返回, 的各種非同步測試方案都能很好滿足。

剩下的部分就是跟 UI 相關的了。


容器組件

容器組件的主要目的是傳遞 state 和 actions,看下工具欄的容器組件代碼:

那麼測試用例的目的也是檢查這些,這裡使用了 來模擬 redux 的 store :

很簡單有木有,所以也沒啥可說的了。


UI 組件

這裡以表格組件作為示例,我們將直接來看測試用例是怎麼寫。一般來說 UI 組件我們主要測試以下幾個方面:

是否渲染了正確的 DOM 結構

樣式是否正確

業務邏輯觸發是否正確

下面是測試用例代碼:

得益於設計分層的合理性,我們很容易利用構造 來達到測試目的,結合 和 ,測試用例依然保持簡單的節奏。


總結

以上就是這個場景完整的測試用例編寫思路和示例代碼,文中提及的思路方法也完全可以用在 、 項目上。完整的代碼內容在 這裡 (重要的事情多說幾遍,各位童鞋覺得好幫忙去給個 哈)。

最後我們可以利用覆蓋率來看下用例的覆蓋程度是否足夠(一般來說不用刻意追求 100%,根據實際情況來定):

單元測試是 TDD 測試驅動開發的基礎。從以上整個過程可以看出,好的設計分層是很容易編寫測試用例的,單元測試不單單只是為了保證代碼質量:他會逼著你思考代碼設計的合理性,拒絕麵條代碼

借用 Clean Code 的結束語:

2005 年,在參加于丹佛舉行的敏捷大會時,Elisabeth Hedrickson 遞給我一條類似 Lance Armstrong 熱銷的那種綠色腕帶。這條腕帶上面寫著「沉迷測試」(Test Obsessed)的字樣。我高興地戴上,並自豪地一直系著。自從 1999 年從 Kent Beck 那兒學到 TDD 以來,我的確迷上了測試驅動開發。

不過跟著就發生了些奇事。我發現自己無法取下腕帶。不僅是因為腕帶很緊,而且那也是條精神上的緊箍咒。那腕帶就是我職業道德的宣告,也是我承諾盡己所能寫出最好代碼的提示。取下它,彷彿就是違背了這些宣告和承諾似的。

所以它還在我的手腕上。在寫代碼時,我用餘光瞟見它。它一直提醒我,我做了寫出整潔代碼的承諾。

作者:deepfunc

https://segmentfault.com/a/1190000015935519

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 JavaScript 的精彩文章:

大廠 H5 開發實戰手冊
Hi,你的10G大數據免費學習資料包到了,請簽收!

TAG:JavaScript |