前端單元測試總結


1.為什么需要單元測試

  • 正確性:測試可以驗證代碼的正確性,在上線前做到心里有底
  • 自動化:當然手工也可以測試,通過console可以打印出內部信息,但是這是一次性的事情,下次測試還需要從頭來過,效率不能得到保證。通過編寫測試用例,可以做到一次編寫,多次運行
  • 解釋性:測試用例用於測試接口、模塊的重要性,那么在測試用例中就會涉及如何使用這些API。其他開發人員如果要使用這些API,那閱讀測試用例是一種很好地途徑,有時比文檔說明更清晰
  • 驅動開發,指導設計:代碼被測試的前提是代碼本身的可測試性,那么要保證代碼的可測試性,就需要在開發中注意API的設計,TDD將測試前移就是起到這么一個作用
  • 保證重構:互聯網行業產品迭代速度很快,迭代后必然存在代碼重構的過程,那怎么才能保證重構后代碼的質量呢?有測試用例做后盾,就可以大膽的進行重構

2.前端相關的單元測試技術

2.1 測試框架

目前,前端的測試框架很多,像QUnit、jasmine、mocha、jest、intern等框架,這些框架各有特點,簡單描述下,感興趣的可以具體研究:

  • Qunit: 該框架誕生之初是為了jquery的單元測試,后來獨立出來不再依賴於jquery本身,但是其身上還是脫離不開jquery的影子
  • jasmine: Behavior-Drive development(BDD)風格的測試框架,在業內較為流行,功能很全面,自帶asssert、mock功能
  • mocha: node社區大神tj的作品,可以在node和browser端使用,具有很強的靈活性,可以選擇自己喜歡的斷言庫,選擇測試結果的report
  • intern: 看官方介紹該測試框架功能極其全面,似乎囊括了業內跟測試相關的所有功能

2.2 斷言庫

  • chai:應該是目前組流行的斷言庫了,支持TDD(assert)、BDD(expect、should)兩個風格的斷言庫
    var chai = require('chai'); 
    
    var assert = chai.assert; // typef assert === 'object'
    chai.should(); // 對Obejct.prototype進行拓展
  •  should.js: TJ的另外一個開源貢獻
  • expect.js:BDD風格的另外一個斷言庫,基於should.js,是mini版的BDD庫
  • assert(node自帶核心模塊): 可以在node中使用的斷言模塊

 

2.3 mock庫
先來說說為什么需要mock吧:需要測試的單元依賴於外部的模塊,而這些依賴的模塊具有一些特點,例如不能控制、實現成本較高、操作危險等原因,不能直接使用依賴的模塊,這樣情況下就需要對其進行mock,也就是偽造依賴的模塊。例如在使用XMLHttpRequest時,需要模擬http statusCode為404的情況,這種情況實際很難發生,必然要通過mock來實現測試。

  • sinon.js: 目前使用最多的mock庫,將其分為spies、stub、fake XMLHttpRequest、Fake server、Fake time幾種,根據不同的場景進行選擇。

2.4 test runner

  • karma: 設置測試需要的框架、環境、源文件、測試文件等,配置完后,就可以輕松地執行測試。

3.單元測試技術的實現原理

  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函數


4.如何寫單元測試用例
 

4.1原則

  • 測試代碼時,只考慮測試,不考慮內部實現
  • 數據盡量模擬現實,越靠近現實越好
  • 充分考慮數據的邊界條件
  • 對重點、復雜、核心代碼,重點測試
  • 利用AOP(beforeEach、afterEach),減少測試代碼數量,避免無用功能
  • 測試、功能開發相結合,有利於設計和代碼重構

4.2 TDD

一句話簡單來說,就是先寫測試,后寫功能實現。TDD的目的是通過測試用例來指引實際的功能開發,讓開發人員首先站在全局的視角來看待需求。具體定義可以查看維基;

就個人而言,TDD不是一個技術,而是一種開發的指導思想。在目前互聯網的開發環境下,業務開發很難做到TDD開發,一是因為需要更多時間編寫單元測試用例;二是要求非常了解業務需求;三是要求開發人員有很強的代碼設計能力。但是當我們寫組件、工具方法、類庫的時候,TDD就可以得到很好地使用。

4.3 BDD

行為驅動開發要求更多人員參與到軟件的開發中來,鼓勵開發者、QA、相關業務人員相互協作。BDD是由商業價值來驅動,通過用戶接口(例如GUI)理解應用程序。詳見維基.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM