首頁  >  文章  >  web前端  >  angularjs中的單元測試實例_AngularJS

angularjs中的單元測試實例_AngularJS

WBOY
WBOY原創
2016-05-16 16:28:531418瀏覽

當ng專案越來越大的時候,單元測試就要提上日程了,有的時候團隊是以測試先行,有的是先實現功能,後面再測試功能模組,這個各有利弊,今天主要說說利用karma和jasmine來進行ng模組的單元測試.

什麼是Karma

karma是一個單元測試的運行控制框架,提供以不同環境來運行單元測試,比如chrome,firfox,phantomjs等,測試框架支持jasmine,mocha,qunit,是一個以nodejs為環境的npm模組.

安裝測試相關的npm模組建議使用----save-dev參數,因為這是開發相關的,一般的運行karma的話只需要下面兩個npm指令

複製程式碼 程式碼如下:

npm install karma --save-dev
npm install karma-junit-reporter --save-dev

安裝karma的時候會自動的安裝一些常用的模組,參考karma程式碼裡的package.json檔案的peerDependencies屬性

複製程式碼 程式碼如下:

 "peerDependencies": {
        "karma-jasmine": "~0.1.0",
        "karma-requirejs": "~0.2.0",
        "karma-coffee-preprocessor": "~0.1.0",
        "karma-html2js-preprocessor": "~0.1.0",
        "karma-chrome-launcher": "~0.1.0",
        "karma-firefox-launcher": "~0.1.0",
        "karma-phantomjs-launcher": "~0.1.0",
        "karma-script-launcher": "~0.1.0"
  }

然後一個典型的運行框架通常都需要一個設定檔,在karma裡可以是一個karma.conf.js,裡面的程式碼是一個nodejs風格的,一個普通的例子如下:

複製程式碼 程式碼如下:

module.exports = function(config){
  config.set({
    // 下面files裡的基礎目錄
    basePath : '../',
    // 測試環境需要載入的JS資訊
    files : [
      'app/bower_components/angular/angular.js',
      'app/bower_components/angular-route/angular-route.js',
      'app/bower_components/angular-mocks/angular-mocks.js',
      'app/js/**/*.js',
      '測試/單元/**/*.js'
    ],
    // 是否自動監聽上面檔案的變更自動執行測試
    autoWatch : true,
    // 應用的測試架構
    frameworks: ['jasmine'],
    // 用什麼環境測試程式碼,這裡是chrome`
    browsers : ['Chrome'],
    // 用到的插件,例如chrome瀏覽器與jasmine插件
    plugins : [
            'karma-chrome-launcher',
            'karma-firefox-launcher',
            'karma-jasmine',
            'karma-junit-reporter'
            ],
    // 測試內容的輸出及導出用的模組名稱
    reporters: ['progress', 'junit'],
    // 設定輸出測試內容檔案的資訊
    junitReporter : {
      outputFile: 'test_out/unit.xml',
      suite: 'unit'
    }

  });
};

這裡要注意的時,上面的插件大部分都不需要單獨安裝,因為安裝karma的時候已經安裝了,這裡只有karma-junit-reporter導出插件需要單獨安裝,想要了解更多的關於配置文件的資訊可以,點這裡

karma就講到這裡,想了解更多關於它的資訊可以,點這裡

什麼是jasmine

Jasmine is a behavior-driven development framework for testing JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM. And it has a clean, obvious syntgrite that youf clean, obvious syntgrite 🎜>

上面是jasmine官方文件裡對它的解釋,下面用中文簡單的翻譯下

jasmine是一個行為驅動開發的測試框架,不依賴任何js框架以及dom,是一個非常乾淨以及友好API的測試庫.

下面簡單的以一個例子來說明它的用法

定義一個測試檔指令為test.js


複製程式碼 程式碼如下:
describe("A spec (with setup and tear-down)", function() {
  var foo;
  beforeEach(function() {

    foo = 0;
    foo = 1;
  });

  afterEach(function() {

    foo = 0;
  });

  it("is just a function, so it can contain any code", function() {

    expect(foo).toEqual(1);
  });

  it("can have more than one expectation", function() {

    expect(foo).toEqual(1);
    expect(true).toEqual(true);
  });
});

上面的例子來自於官網,這裡只說下幾個重要的API,更多的用法請,

點這裡

1.首先任何一個測試案例以describe函數來定義,它有兩參數,第一個用來描述測試大體的中心內容,第二個參數是一個函數,裡面寫一些真實的測試代碼

2.it是用來定義單一特定測試任務,也有兩個參數,第一個用來描述測試內容,第二個參數是一個函數,裡面存放一些測試方法

3.expect主要用來計算一個變數或一個表達式的值,然後用來跟期望的值比較或做一些其它的事件

4.beforeEach與afterEach主要是用來在執行測試任務之前和之後做一些事情,上面的例子就是在執行之前改變變數的值,然後在執行完成之後重置變數的值

最後要說的是,describe函數裡的作用域跟普通JS一樣都是可以在裡面的子函數裡訪問的,就像上面的it訪問foo變量

想要執行上面的測試範例可以透過karar來運作,指令範例如下:

複製程式碼 程式碼如下:
karma start test/karma.conf.js

下面我們重點的說說ng裡的控制器,指令,服務模組的單元測試.

NG的單元測試

因為ng本身框架的原因,模組都是透過di來載入以及實例化的,所以為了方便配合jasmine來編寫測試腳本,所以官方提供了angular-mock.js的一個測試工具類別來提供模組定義,加載,注入等.

下面說說ng-mock裡的一些常用方法

1.angular.mock.module 此方法同樣在window命名空間下,非常方便呼叫

module是用來配置inject方法注入的模組資訊,參數可以是字串,函數,物件,可以像下面這樣使用


複製程式碼 程式碼如下:
beforeEach(module('myApp.filters'));
beforeEach(module(function($provide) {

      $provide.value('version', 'TEST_VER');
}));

它一般用在beforeEach方法裡,因為這個可以確保在執行測試任務的時候,inject方法可以獲取到模組配置

1.angular.mock.inject 此方法同樣在window命名空間下,非常方便呼叫

inject是用來注入上面配置好的ng模組,方面在it的測試函數裡調用,常見的調用例子如下:

複製程式碼 程式碼如下:

angular.module('myApplicationModule', [])
      .value('模式', '應用程式')
      .value('版本', 'v1.0.1');


  描述('MyApp', function() {

    // 您需要載入要測試的模組,
    // 預設僅載入“ng”模組。
    beforeEach(module('myApplicationModule'));


    // Inject() 用於注入所有給定函數的參數
    it('應該提供一個版本',inject(function(mode, version) {
      Expect(version).toEqual('v1.0.1');
      Expect(mode).toEqual('app');
    }));


    // 注入和模組方法也可以在 it 或 beforeEach
內部使用     it('應該覆寫一個版本並測試注入的新版本', function() {
      // module() 接受函數或字串(模組別名)
      模組(函數($提供){
        $provide.value('版本', '覆蓋'); // 在這裡覆蓋版本
      });

      注入(函數(版本){
        Expect(version).toEqual('覆蓋');
      });
    });
  });

上面是官方提供的一些注入範例,程式碼很好看懂,其實inject裡面就是利用angular.inject方法創建的一個內建的依賴注入實例,然後裡面的模組注入跟普通ng模組裡的依賴處理是一樣的的

簡單的介紹完成ng-mock之後,我們下面分別以控制器,指令,過濾器來寫一個簡單的單元測試。

ng裡控制器的單元測試

定義了一個簡單的控制器

複製程式碼以下程式碼:

var myApp = angular.module('myApp',[]);

    myApp.controller('MyController', function($scope) {
      $scope.spices = [{"name":"pasilla", "spiciness":"mild"},
                       {"name":"jalapeno", "spiciness":"熱熱熱!"},
                       {"name":"habanero", "spiciness":"LAVA HOT!!"}];
      $scope.spice = "你好費南!";
});

然後我們寫了一個測試腳本

複製程式碼以下程式碼:

描述('myController函數', function() {

  描述('myController', function() {
    var $scope;

    beforeEach(module('myApp'));

    beforeEach(注入(function($rootScope, $controller) {
      $scope = $rootScope.$new();
      $controller('MyController', {$scope: $scope});
    }));

    it('應以 3 種香料創造「香料」模型', function() {
      Expect($scope.spices.length).toBe(3);
    });

    it('應該設定spice的預設值', function() {
      Expect($scope.spice).toBe('你好費南!');
    });
  });

});

上面利用了$rootScope來建立子作用域,然後把這個參數傳進控制器的建置方法$controller裡去,最後會執行上面的控制器裡的方法,然後我們檢查子作用域裡的資料庫數量字串以及變數是否滿足期望的值。

想要了解更多關於ng裡控制器的信息,可以點擊這裡

ng裡指令的單元檢定

定義了一個簡單的指令

複製程式碼程式碼如下:

var app = angular.module('myApp', []);

app.directive('aGreatEye', function () {
    返回{
        限制:'E',
        替換:true,
        範本:'

無蓋,火焰環繞,1 次

'
    };
});

然後我們寫了一個簡單的測試腳本

複製程式碼程式碼如下:

描述('單元測試偉大的報價',函數(){
    var $compile;
    var $rootScope;

    // 載入 myApp 模組,其中包含指令
    beforeEach(module('myApp'));

    // 儲存對 $rootScope 和 $compile
的引用     // 所以它們可用於此描述區塊中的所有測試
    beforeEach(注入(函數(_$compile_, _$rootScope_){
      // 符合
時,注入器會解開參數名稱周圍的底線(_)       $compile = _$compile_;
      $rootScope = _$rootScope_;
    }));

    it('以適當的內容取代元素', function() {
        // 編譯中包含指令
的HTML         var element = $compile("")($rootScope);
        // 觸發所有手錶,因此將計算範圍表達式 1
        $rootScope.$digest();
        // 檢查編譯的元素是否包含模板化內容
        Expect(element.html()).toContain("無蓋,被火焰纏繞,2次");
    });
});

上面的例子來自官方提供的,最後上面的指令將在html裡使用

複製程式碼程式碼如下:

大眼睛>

測試腳本裡首先註入$compile和$rootScope兩個服務,一個用於編譯html,一個用於創建作用域用,注意這裡的_,默認ng裡注入的服務隨後加上_時,最後會被ng處理掉的,這兩個服務保存在內部的兩個變數裡,方便下面的測試實例能呼叫到

$compile方法決定原指令html,然後在傳回的函式中確定$rootScope,這樣就完成了作用域與視圖的綁定,最後呼叫$rootScope.$digest來觸發所有監聽,保證視圖裡的模型內容得到更新

然後取得目前指令對應元素的html內容與期望值進行比較。

想要了解更多關於ng裡的指令的信息,可以點擊這裡

ng裡的過濾器單元測試

定義了一個簡單的過濾器

複製程式碼以下程式碼:

var app = angular.module('myApp', []);
app.filter('內插', ['版本', 函數(版本) {
    返回函數(文字){
      return String(text).replace(/%VERSION%/mg, version);
    };
  }]);

然後寫了一個簡單的測試腳本
複製程式碼如下程式碼:

describe('filter', function() {
  beforeEach(module('myApp'));


  describe('interpolate', function() {

    beforeEach(module(function($provide) {
      $provide.value('version', 'TEST_VER');
    }));


    it('should replace VERSION', inject(function(interpolateFilter) {
      expect(interpolateFilter('before %VERSION% after')).toEqual('before TEST_VER after');
    }));
  });
});

上面的程式碼先配置過濾器模組,然後定義一個version值,因為interpolate依賴這個服務,最後用inject注入interpolate過濾器,注意這裡的過濾器後面得加上Filter後綴,最後傳入文本內容到濾波器函數裡執行,與期望值進行對比.

總結

利用測試來開發NG有很多好處,可以保證模組的穩定性,還有一點就是能夠深入的了解ng的內部運行機制,所以建議用ng開發的同學趕緊把測試補上吧!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn