Elaine's Blog 朝著 senior 前進的工程師

單元測試

2018-09-15

  1. 測試可以確保得到預期的結果
  2. 作為現有程式碼行為的描述
  3. 促使開發者寫可測試的程式碼,一般可測試的程式碼可讀性也會高一點
  4. 如果相依的元件有修改,受影響的元件能在測試中發現錯誤

測試類型

  • 單元測試
    • 單元可以是一個函數,也可以是一個模塊或一個類別
    • 基本特徵就是只要輸入不變,必定返回同樣的輸出
    • 越容易單元測試,就代表它的模塊化結構越好,模塊之間的耦合越弱
    • React 的組件化和函數式程式,適合進行單元測試
  • 功能測試
    • 相當於是黑盒測試,測試者不瞭解進程的內部情況,不需要具備編程語言的專門知識,只知道進程的輸入、輸出和功能,從用户的角度針對軟體界面、功能和外部結構進行測試,不考慮內部的邏輯
  • 集成測試
    • 在單元測試的基礎上,將所有模塊按照設計要求組裝成子系統或者系統,進行測試
  • 冒煙測試
    • 在正式全面的測試之前,對主要功能進行的與測試,確認主要功能是否滿足需要,軟體是否能正常運行

開發模式

  • 測試驅動開發 TDD (Testing Driven Development)
    • 先寫測試,後寫功能實現
    • 強調的是一種開發方式,以測試來驅動整個專案,即先根據接口完成測試程式碼,再編寫功能程式碼
  • 行為驅動測試 BDD (Behavior Driven Development)
    • 強調的是寫測試的風格,注重以通用語言表達測試,讓整個專案的各個成員(開發者、QA、相關業務人員)都能看懂測試,甚至編寫測試
  • TDD 和 BDD 有各自的使用場景,BDD 一般偏向於系統功能和業務邏輯的自動化測試設計;而 TDD 在快速開發並測試功能模塊的過程中則更加高效,以快速完成開發為目的

單元測試技術的實現原理

  1. 測試框架
    • 判斷內部是否存在異常,存在則 console 出對應的 text 信息
  2. 斷言庫
    • 當 actual 值與 expect 值不一樣時,就拋出異常,供外部測試框架檢測到,這就是為什麼有些測試框架可以自由選擇斷言庫的原因,只要可以拋出異常,外部測試框架就可以工作
  3. mock 函數
    • 創建一個新的函數,用這個函數來取代原來的函數,同時在這個新函數上添加一些額外的屬性,例如 called、calledWithArguments 等信息
function describe (text, fn) {
    try {
        fn.apply(...);
    } catch(e) {
        assert(text)
    }
}
function fn () {
    while (...) {
        beforeEach();
        it(text, function () {
            assert();
        });
        afterEach();
    }
}
function it(text, fn) {
  ...
  fn(text)
  ...
}
function assert (expect, actual) {
    if (expect not equla actual ) {
        throw new Error(text);
    }
}
function fn () {
  ...
}

function spy(cb) {
  var proxy = function () {
    ...
  }
  proxy.called = false;
  proxy.returnValue = '...';
  ...
  return proxy;
}

var proxy = spy(fn); // 得到一个 mock 函数

如何寫單元測試

  1. 只考慮測試,不考慮內部實現
  2. 不要做無謂的斷言
  3. 讓每個單元測試保持獨立
  4. 所有的方法都應該寫單元測試
  5. 充分考慮數據的邊界條件
  6. 對重點、複雜、核心代碼,重點測試
  7. 利用 AOP (beforeEach、afterEach),減少測試代碼數量,避免無用功能
  8. 使用最合適的斷言方式

測試技巧

  1. BDD => given 給定、when 當、then 然後

    • 我有一個筆記列表,當我試著刪除一個筆記時,然後筆記應從列表中刪除
  2. 每個測試之間都不能互相污染,可以利用 afterEach(fn) 或 beforeEach(fn)

  3. 只跑有更新的測試,不用跑全部

jest `gst | grep spec | cut -d":" -f2` -u

node node_modules/jest/bin/jest.js `gst | grep spec | cut -d":" -f2` -u

測試覆蓋率

測試覆蓋率是一個測試指標,用來描述測試用例的程式碼是否都被執行

指標

  1. 行覆蓋率(line coverage):是否每一行都執行了
  2. 函數覆蓋率(function coverage):是否每一個函數都調用了
  3. 分支覆蓋率(branch coverage):是否每個 if 代碼塊都執行了
  4. 語句覆蓋率(statement coverage):是否每個語句都執行了

代码覆盖率工具 Istanbul 入门教程


下一篇 Jest 學習筆記

Content