国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

在JavaScript的AngularJS庫中進行單元測試的方法

2019-11-20 12:11:54
字體:
來源:轉載
供稿:網友

開發者們都一致認為單元測試在開發項目中十分有好處。它們幫助你保證代碼的質量,從而確保更穩定的研發,即使需要重構時也更有信心。

201562393334308.png (257×221)

 測試驅動開發流程圖

AngularJS的代碼聲稱其較高的可測性確實是合理的。單單文檔中列出端對端的測試實例就能說明。就像AngularJS這樣的項目雖然都說單元測試很簡單但真正做好卻不容易。即使官方文檔中以提供了詳盡的實例,但在我的實際應用中卻還是很有挑戰。這里我就簡單示范一下我是怎么操作的吧.

Instant Karma

Karma 是來Angular團隊針對JavaScript開發的一個測試運行框架。它很方便的實現了自動執行測試任務從而替代了繁瑣的手工操作(好比回歸測試集或是加載目標測試的依賴關系)Karma 和Angular的協作就好比花生醬和果凍.

只需要在Karma中定義好配置文件啟動它,接下來它就會在預期的測試環境下的自動執行測試用例。你可以在配置文件中制定相關的測試環境。angular-seed,是我強烈推薦的可以快速實施的方案。在我近期的項目中Karma 的配置如下:
 

module.exports = function(config) {  config.set({    basePath: '../',     files: [      'app/lib/angular/angular.js',      'app/lib/angular/angular-*.js',      'app/js/**/*.js',      'test/lib/recaptcha/recaptcha_ajax.js',      'test/lib/angular/angular-mocks.js',      'test/unit/**/*.js'    ],     exclude: [      'app/lib/angular/angular-loader.js',      'app/lib/angular/*.min.js',      'app/lib/angular/angular-scenario.js'    ],     autoWatch: true,     frameworks: ['jasmine'],     browsers: ['PhantomJS'],     plugins: [      'karma-junit-reporter',      'karma-chrome-launcher',      'karma-firefox-launcher',      'karma-jasmine',      'karma-phantomjs-launcher'    ],     junitReporter: {      outputFile: 'test_out/unit.xml',      suite: 'unit'    }   })}


這個跟angular-seed的默認配置類似只不過有以下幾點不同:

  •     需要更改瀏覽器從Chrome 轉到PhantomJS, 這樣每次跳轉時無需再打開新的瀏覽器窗口,但在OSX系統會有窗口延遲。所以這個插件還有瀏覽器設置都做了更改。
  •     由于我的應用需要引用Google的Recaptcha服務因此添加了依賴的recaptcha_ajax.js小文件。這個小配置就像在Karma的配置文件中添加一行代碼那么簡單。

autoWatch確實是個很酷的設置,它會讓Karma在有文件更改時自動回歸你的測試用例。你可以這樣安裝Karma:
 

npm install karma

angular-seed 提供了一個簡單的腳本inscripts/test.sh去觸發Karma的測試。


用Jasmine設計測試用例

當使用Jasmine----一種行為驅動開發模式的JavaScript測試框架為Angular設計單元測試用例時大部分的資源都已可獲取。

這也就是我接下來要說的話題。

如果你要對AngularJS controller做單元測試可以利用Angular的依賴注入dependency injection 功能導入測試場景中controller需要的服務版本還能同時檢查預期的結果是否正確。例如,我定義了這個controller去高亮需要導航去的那個頁簽:
 

app.controller('NavCtrl', function($scope, $location) {  $scope.isActive = function(route) {    return route === $location.path();  };})

如果想要測試isActive方法,我會怎么做呢?我將檢查$locationservice 變量是否返回了預期值,方法返回的是否預期值。因此在我們的測試說明中我們會定義好局部變量保存測試過程中需要的controlled版本并在需要時注入到對應的controller當中。然后在實際的測試用例中我們會加入斷言來驗證實際的結果是否正確。整個過程如下:
 

describe('NavCtrl', function() {  var $scope, $location, $rootScope, createController;   beforeEach(inject(function($injector) {    $location = $injector.get('$location');    $rootScope = $injector.get('$rootScope');    $scope = $rootScope.$new();     var $controller = $injector.get('$controller');     createController = function() {      return $controller('NavCtrl', {        '$scope': $scope      });    };  }));   it('should have a method to check if the path is active', function() {    var controller = createController();    $location.path('/about');    expect($location.path()).toBe('/about');    expect($scope.isActive('/about')).toBe(true);    expect($scope.isActive('/contact')).toBe(false);  });});

使用整個基本的結構,你就能設計各種類型的測試。由于我們的測試場景使用了本地的環境來調用controller,你也可以多加上一些屬性接著執行一個方法清除這些屬性,然后再驗證一下屬性到底有沒有被清除。

$httpBackendIs Cool

那么要是你在調用$httpservice請求或是發送數據到服務端呢?還好,Angular提供了一種

$httpBackend的mock方法。這樣的話,你就能自定義服務端的響應內容,又或是確保服務端的響應結果能和單元測試中的預期保持一致。

具體細節如下:
 

describe('MainCtrl', function() {  var $scope, $rootScope, $httpBackend, $timeout, createController;  beforeEach(inject(function($injector) {    $timeout = $injector.get('$timeout');    $httpBackend = $injector.get('$httpBackend');    $rootScope = $injector.get('$rootScope');    $scope = $rootScope.$new();      var $controller = $injector.get('$controller');     createController = function() {      return $controller('MainCtrl', {        '$scope': $scope      });    };  }));   afterEach(function() {    $httpBackend.verifyNoOutstandingExpectation();    $httpBackend.verifyNoOutstandingRequest();  });   it('should run the Test to get the link data from the go backend', function() {    var controller = createController();    $scope.urlToScrape = 'success.com';     $httpBackend.expect('GET', '/slurp?urlToScrape=http:%2F%2Fsuccess.com')      .respond({        "success": true,        "links": ["http://www.google.com", "http://angularjs.org", "http://amazon.com"]      });     // have to use $apply to trigger the $digest which will    // take care of the HTTP request    $scope.$apply(function() {      $scope.runTest();    });     expect($scope.parseOriginalUrlStatus).toEqual('calling');     $httpBackend.flush();     expect($scope.retrievedUrls).toEqual(["http://www.google.com", "http://angularjs.org", "http://amazon.com"]);    expect($scope.parseOriginalUrlStatus).toEqual('waiting');    expect($scope.doneScrapingOriginalUrl).toEqual(true);  });});

正如你所見,beforeEach call其實都很類似,唯一不同的是我們是從injector獲取$httpBackend而并非直接獲取。即使如此,創建不同的測試時還會有一些明顯的不同之處。對初學者來說,會有一個afterEachcall 方法來確保$httpBackend在每次用例執行后不會有明顯的異常請求。如果你觀察一下測試場景的設置和$httpBackend方法的應用就會會發現有那么幾點不是那么直觀的。
 

實際上調用$httpBackend的方法也算是簡單明了但還不夠――我們還得在傳值給$scope.$apply的方法中把調用封裝到實際測試中的$scope.runTest方法上。這樣在$digest被觸發后才能處理HTTP請求。而如你所見直到我們調用$httpBackend.flush()方法后$httpBackend才會被解析,這也就保證了我們能在調用過程中去驗證返回的結果是否正確(在上面的示例中,controller的$scope.parseOriginalUrlStatusproperty屬性將被傳遞給調用者,我們也因此能實時監控)

接下來的幾行代碼都是在調用過程中檢測$scopethat屬性的斷言。很酷吧?

提示:在某些單元測試中,用戶習慣把沒有$的范圍標記為變量。這個在Angular文檔中并沒有強制要求或是過分強調,只是我在使用中為了提高可讀性和一致性才使用$scopelike這種方式。

結論

也許這就是我做起來對其他人而言只是自然而然能做到的事情之一,但是學習使用Angular編寫單元測試一開始對我而言確實是相當痛苦的。我發現自己對如何開始的理解大多來自互聯網上各種博客文章和資源的拼拼湊湊,沒有真正一致或明確的最佳實踐,而是通過自然而然隨意的選擇。我想針對我最終得到的成果提供一些文檔,以幫助那些也許還在坑里面掙扎的其他人,畢竟他們只是想要編寫代碼而已,而非不得不去了解Angular和Jasmine中所有的怪異特性和獨特用法。因此我希望這篇文章能對你有些許幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 四川省| 绥化市| 溧阳市| 七台河市| 孟州市| 陇川县| 武山县| 抚宁县| 长沙市| 渭源县| 衡阳县| 曲麻莱县| 轮台县| 离岛区| 古浪县| 米脂县| 江孜县| 获嘉县| 泗阳县| 南宫市| 江孜县| 闻喜县| 腾冲县| 丹阳市| 扶风县| 襄汾县| 辉县市| 丹棱县| 阜阳市| 来凤县| 随州市| 清流县| 翁牛特旗| 新竹市| 梓潼县| 北海市| 卓资县| 灯塔市| 鄱阳县| 兴文县| 凤山市|