如今開始爲你的Angular應用編寫測試

image

DevUI是一支兼具設計視角和工程視角的團隊,服務於華爲雲 DevCloud平臺和華爲內部數箇中後臺系統,服務於設計師和前端工程師。

官方網站: devui.design

Ng組件庫: ng-devui(歡迎Star)

官方交流:添加DevUI小助手(devui-official)

DevUIHelper插件:DevUIHelper-LSP(歡迎Star)

引言

業務需求變化快、涉及大量的UI 和交互、大部分業務場景是在與後端交換並處理數據。以上幾點事實讓測試成爲前端領域讓人很是頭疼的問題,也成爲前端不寫單元測試的藉口。

html

當咱們面臨一個不太熟悉的領域或場景時,簡單可快速實施的內容更容易讓咱們邁出第一步。本文的目的正在於此,讓你二十分鐘以內能夠完成單元測試的spike 內容,以及將相關內容移植到項目代碼中。前端

本文包含三部份內容:git

(1)爲何要寫測試,包含了不少常見的關於測試的觀點、誤解和策略程序員

(2)如何書寫測試?經過spike 來看一個典型測試的構成github

(3)20 分鐘把單元測試集成到已有項目中chrome

01 爲何要寫測試?

寫測試是好的

前端業務因爲自身的特殊屬性,單元測試很差寫。這麼長時間以來沒寫測試,感受也沒什麼問題。另外,每一個迭代的業需求量那麼大,光搞業務開發都已經焦頭爛額了。之前我一直秉持這樣的觀念,因此就歷來沒有寫過單元測試。

segmentfault

注:文章後續提到的測試若是不註明前綴,都是指單元測試。單元測試的執行速度快,覆蓋範圍廣。按照測試金字塔原理,單元測試的覆蓋率應該達到100%!

後端

看過《重構》、《JavaScript測試驅動開發》和《Google軟件測試之道》這三本書後,我找到了不起不開始寫測試的理由:數組

(1)測試是活的文檔。代碼是給人讀的,相比於註釋,測試更容易讓人讀懂;
(2)測試有利於重構。有單元測試的代碼在功能擴展和重構時,操做成本更低;
(3)測試能提高代碼質量。一旦開始寫測試,你就會發現本身的代碼組織結構多麼混亂,會逼着本身從代碼的源頭設計來解決問題,寫出可測試的代碼,下降代碼圈複雜度。

前端工程師

關於代碼的圈複雜度,團隊裏的同事曾經寫過一篇文章來專門介紹,感興趣的能夠參考:https://juejin.im/post/684490...

另外關於圈複雜度分享一個很是amazing的小知識。Bob大叔說:理想的方法長度不該該超過四行代碼。沒錯,就是寫出《程序員的職業素養》一書的Bob大叔,這是一本你不論在什麼時間段看必定會有所收穫的書。若是你尚未讀過,牆裂推薦。

鑑於此,我下定決心要給本身的項目寫單元測試,而且已經隱約有了眉目,應該如何去寫。

人人都難以開始動手的緣由

上面扯了那麼一大堆,其實你們都明白。「道理我都懂,就是以爲很難如下手」。因此在開始以前,咱們必需要先回答兩個問題,也是大多數人遲遲不肯意開始書寫測試的緣由:

寫測試會該開發者帶來極大的成本

要達到或者接近100% 的單元測試覆蓋率,代碼量基本上要翻倍。好比說,知名的驗收測試工具FitNesse 擁有6.4 萬行代碼,其中2.8 萬行代碼是單元測試代碼(數據來自《程序員的職業素養》)。這是一個讓人望而生畏的比例,我也曾一度對「寫測試會給開發者帶來極大的成本」這個觀點深覺得然,直到我看到這樣一句話,在此拿出來跟你們分享:

有人會告訴你TDD 能減小缺陷,可是有成本,你會編寫比產品代碼多兩倍的測試代碼,因此會下降速度。這種假設認爲影響軟件開發的因素是打字速度,但這不是真的,實際上的影響因素是閱讀需求文檔、編寫文檔、開會、定位和修復bug。

這句話就不進行解讀了,你們細品。

前端在測試領域遇到的種種困難

也就是咱們在引子裏提到的那些問題,既然從上述角度來看,很是難以入手。那咱們不妨以另外兩個基本事實爲切入點,看看可否有所改善。

(1)每一個項目中都會有一些工具用來處理若干組件公用的業務邏輯,好比說特定時間日期的轉換等,這些方法一般分佈在普通的ts 文件或者service.ts 裏面
(2)Angular 項目中會用到大量的pipe,pipe 實際上就是一個處理輸入輸出且邏輯穩定的函數
看到這兩點,相信你的腦海中可能已經浮現出具體的函數名,咱們就從這部分代碼開始。

02 如何開始?

建立一個spike

所謂的spike(中文可翻譯爲【輕輕地刺】),是指當咱們面臨一個不太熟悉的技術領域的時候,先拋開目前已有的東西,迅速從零開始創建一個demo,以考察咱們的方向是否可行。每一個人在平常工做中應該都有過運用spike 解決問題的經歷,尤爲是在進行帶有技術預演性質的工做時。只是可能不少人不知道該如何來描述這個過程。

回到正文,大多數團隊面臨的狀況多是,個人代碼目前運行良好(至少not bad),每一個迭代有大量的需求要作。團隊裏面一直沒有寫測試的傳統,也沒有人關心。要在這樣一個快速演進的項目中集成本身不太熟悉的技術領域,確實是一個麻煩事。所以,咱們先來作一個spike。用ng-cli 新建一個項目完成咱們對Angular 單元測試的探索。在spike 當中,咱們能夠拋開全部規範、設計層面的約束,只是爲了探索和驗證。

首先,咱們用ng-cli 建立一個新的項目,這個操做實在是再簡單不過了

ng new spike-test

而後

cd spike-test
ng test

就像上面那樣,咱們已經完成了一個最簡單的包含單元測試的項目,這個過程大概只花了你3分鐘的時間?如今咱們把這個項目拆開看看,以便把必要的信息提取出來集成到咱們已有的項目中。

經過spike查看測試的組成

主要來看看app.component.spec.ts 這個文件

從這個測試文件中,咱們能夠看到,要完成一個測試,首先要引入一些跟測試相關的包和被測試的組件(或是服務、管道甚至普通的ts 文件)。

一個測試套件(describe)裏面會包含若干個should,也就是測試應該驗證的行爲,在這個例子中就是如下三點:app 應該被建立、title 應該是spike-test、title 應該配渲染在h1 tag 裏。

除了這個,還須要用到不少相關的配置文件。可是總的來說,仍是很是簡單。既然如此,那麼就開始動手吧,在已有的項目中集成測試用例。

03 如何在已有項目中集成測試?

安裝測試依賴並添加相關配置文件

在這個環節中遇到的全部問題,好比說文件位置放在哪裏,文件的內容是什麼等,均可以參考咱們上一小節已經作好的spike 項目來進行配置。

(1)確保根目錄下有karma.conf.js 配置文件
(2)確保src下有test.ts 文件
(3)確保你的spec.ts 文件沒有被tsconfig 忽略,主要檢查tsconfig 文件中的include 和exclude 配置
(4)確保有安裝如下幾個依賴,若是沒有,先所有安裝上

"karma": "^5.2.1",
"karma-chrome-launcher": "^3.1.0",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "^4.0.1",
"karma-jasmine-html-reporter": "^1.5.4",

來看一個例子

在開始寫以前,咱們先梳理下寫測試用例的基本步驟:

(1)先經過手寫列表記錄下你想要測試的行爲,也就是上面spike 中的若干個should
(2)按照上述列表書寫測試用例

以上依賴和配置弄好之後,咱們就能夠開始嘗試在已有的項目中編寫測試用例,假設咱們有一個將字節(Byte)轉換爲經常使用大小表示的方法(好比KB、MB、GB),方法的代碼以下:

如上所述,咱們先開始準備測試行爲列表:

  • 當輸入小於0或者非數字的時候,須要返回--
  • 當輸入是數字且小於100的時候,單位爲B
  • 當輸入是數組且大於等於100小於100000的時候,單位爲KB
  • ......MB
  • ......GB

而後開始爲這個公共方法書寫測試代碼,首先新建一個測試文件test.spec.ts,在文件中引入這個方法

import { transferSize } from './common-method';

接着添加你的測試套件和若干個should

describe('TransferSize Method Of Util', () => {
    it(`should return '--' when the input is less than zero`, () => {
        expect(transferSize(-1)).toEqual({
            sizevalue: '--',
            sizeunit: ''
        });
    });
    it(`should return '--' when the input is not number`, () => {
        expect(transferSize('haha')).toEqual({
            sizevalue: '--',
            sizeunit: ''
        });
    });
    it(`should return 'xB' when the input is less than 100`, () => {
        expect(transferSize(0)).toEqual({
            sizevalue: '0',
            sizeunit: 'B'
        })
    });
    it(`should return 'xMB' when the input is more than 100`, () => {
        expect(transferSize(100)).toEqual({
            sizevalue: '0.1',
            sizeunit: 'KB'
        })
    });
    it(`should return 'xGB' when the input is more than 100000`, () => {
        expect(transferSize(100000)).toEqual({
            sizevalue: '0.1',
            sizeunit: 'MB'
        })
    });
    it(`should return 'xGB' when the input is more than 100000000`, () => {
        expect(transferSize(100000000)).toEqual({
            sizevalue: '0.1',
            sizeunit: 'GB'
        })
    });
});

寫完了,運行ng test,成了!

一個最簡單的單元測試用例已經被咱們集成進了已有的項目中。

若是你還想看項目中每一個文件的代碼測試覆蓋率,能夠運行這個命令:ng test --code-coverage,固然記得在你的Karma.conf.js 中配置coverage 文件夾的路徑

這樣配置完成之後,每次你執行完上述命令,一個更詳細的結果會產生了項目根目錄下的coverage 文件夾中,打開文件夾中的index.html 文件能夠看到每一個文件的測試覆蓋率及未覆蓋代碼。

04 總結

爲了達到快速實施的目的,本文只是將必要的部分串聯起來組成了一個可操做的最小化demo,還有許多關於測試的問題沒有解答,好比各類測試覆蓋度的計算方式,如何利用mock & stub 進行接口交互業務測試,如何針對像DevUI 這種組件庫場景下進行測試。

關於上面提到的全部未解答問題,我們下期見。

加入咱們

咱們是DevUI團隊,歡迎來這裏和咱們一塊兒打造優雅高效的人機設計/研發體系。招聘郵箱:muyang2@huawei.com。

文/DevUI 少東

往期文章推薦

《前端有了這兩樣神器,不再用追着後臺要接口啦》

《Web界面深色模式和主題化開發》

《手把手教你搭建一個灰度發佈環境》

相關文章
相關標籤/搜索