日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
如何在AngularJS中對(duì)控制器進(jìn)行單元測(cè)試

開(kāi)發(fā)者們都一致認(rèn)為單元測(cè)試在開(kāi)發(fā)項(xiàng)目中十分有好處。它們幫助你保證代碼的質(zhì)量,從而確保更穩(wěn)定的研發(fā),即使需要重構(gòu)時(shí)也更有信心。

測(cè)試驅(qū)動(dòng)開(kāi)發(fā)流程圖

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

Instant Karma

Karma是來(lái)Angular團(tuán)隊(duì)針對(duì)JavaScript開(kāi)發(fā)的一個(gè)測(cè)試運(yùn)行框架。它很方便的實(shí)現(xiàn)了自動(dòng)執(zhí)行測(cè)試任務(wù)從而替代了繁瑣的手工操作(好比回歸測(cè)試集或是加載目標(biāo)測(cè)試的依賴關(guān)系)Karma 和Angular的協(xié)作就好比花生醬和果凍.

只需要在Karma中定義好配置文件啟動(dòng)它,接下來(lái)它就會(huì)在預(yù)期的測(cè)試環(huán)境下的自動(dòng)執(zhí)行測(cè)試用例。你可以在配置文件中制定相關(guān)的測(cè)試環(huán)境。angular-seed,是我強(qiáng)烈推薦的可以快速實(shí)施的方案。在我近期的項(xiàng)目中Karma 的配置如下:

 
 
 
 
  1. module.exports = function(config) { 
  2.     config.set({ 
  3.         basePath: '../', 
  4.  
  5.         files: [ 
  6.             'app/lib/angular/angular.js', 
  7.             'app/lib/angular/angular-*.js', 
  8.             'app/js/**/*.js', 
  9.             'test/lib/recaptcha/recaptcha_ajax.js', 
  10.             'test/lib/angular/angular-mocks.js', 
  11.             'test/unit/**/*.js' 
  12.         ], 
  13.  
  14.         exclude: [ 
  15.             'app/lib/angular/angular-loader.js', 
  16.             'app/lib/angular/*.min.js', 
  17.             'app/lib/angular/angular-scenario.js' 
  18.         ], 
  19.  
  20.         autoWatch: true, 
  21.  
  22.         frameworks: ['jasmine'], 
  23.  
  24.         browsers: ['PhantomJS'], 
  25.  
  26.         plugins: [ 
  27.             'karma-junit-reporter', 
  28.             'karma-chrome-launcher', 
  29.             'karma-firefox-launcher', 
  30.             'karma-jasmine', 
  31.             'karma-phantomjs-launcher' 
  32.         ], 
  33.  
  34.         junitReporter: { 
  35.             outputFile: 'test_out/unit.xml', 
  36.             suite: 'unit' 
  37.         } 
  38.  
  39.     }) 

這個(gè)跟angular-seed的默認(rèn)配置類似只不過(guò)有以下幾點(diǎn)不同:

  • 需要更改瀏覽器從Chrome 轉(zhuǎn)到PhantomJS, 這樣每次跳轉(zhuǎn)時(shí)無(wú)需再打開(kāi)新的瀏覽器窗口,但在OSX系統(tǒng)會(huì)有窗口延遲。所以這個(gè)插件還有瀏覽器設(shè)置都做了更改。

  • 由于我的應(yīng)用需要引用Google的Recaptcha服務(wù)因此添加了依賴的recaptcha_ajax.js小文件。這個(gè)小配置就像在Karma的配置文件中添加一行代碼那么簡(jiǎn)單。

 

autoWatch確實(shí)是個(gè)很酷的設(shè)置,它會(huì)讓Karma在有文件更改時(shí)自動(dòng)回歸你的測(cè)試用例。你可以這樣安裝Karma:

 
 
 
 
  1. npm install karma 

angular-seed 提供了一個(gè)簡(jiǎn)單的腳本inscripts/test.sh去觸發(fā)Karma的測(cè)試。

用Jasmine設(shè)計(jì)測(cè)試用例

當(dāng)使用Jasmine----一種行為驅(qū)動(dòng)開(kāi)發(fā)模式的JavaScript測(cè)試框架為Angular設(shè)計(jì)單元測(cè)試用例時(shí)大部分的資源都已可獲取。

這也就是我接下來(lái)要說(shuō)的話題。

如果你要對(duì)AngularJS controller做單元測(cè)試可以利用Angular的依賴注入dependency injection 功能導(dǎo)入測(cè)試場(chǎng)景中controller需要的服務(wù)版本還能同時(shí)檢查預(yù)期的結(jié)果是否正確。例如,我定義了這個(gè)controller去高亮需要導(dǎo)航去的那個(gè)頁(yè)簽:

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

如果想要測(cè)試isActive方法,我會(huì)怎么做呢?我將 檢查$locationservice 變量是否返回了預(yù)期值,方法返回的是否預(yù)期值。因此在我們的測(cè)試說(shuō)明中我們會(huì)定義好局部變量保存測(cè)試過(guò)程中需要的controlled版本并在需要時(shí)注入 到對(duì)應(yīng)的controller當(dāng)中。然后在實(shí)際的測(cè)試用例中我們會(huì)加入斷言來(lái)驗(yàn)證實(shí)際的結(jié)果是否正確。整個(gè)過(guò)程如下:

 
 
 
 
  1. describe('NavCtrl', function() { 
  2.     var $scope, $location, $rootScope, createController; 
  3.  
  4.     beforeEach(inject(function($injector) { 
  5.         $location = $injector.get('$location'); 
  6.         $rootScope = $injector.get('$rootScope'); 
  7.         $scope = $rootScope.$new(); 
  8.  
  9.         var $controller = $injector.get('$controller'); 
  10.  
  11.         createController = function() { 
  12.             return $controller('NavCtrl', { 
  13.                 '$scope': $scope 
  14.             }); 
  15.         }; 
  16.     })); 
  17.  
  18.     it('should have a method to check if the path is active', function() { 
  19.         var controller = createController(); 
  20.         $location.path('/about'); 
  21.         expect($location.path()).toBe('/about'); 
  22.         expect($scope.isActive('/about')).toBe(true); 
  23.         expect($scope.isActive('/contact')).toBe(false); 
  24.     }); 
  25. }); 

使用整個(gè)基本的結(jié)構(gòu),你就能設(shè)計(jì)各種類型的測(cè)試。由于我們的測(cè)試場(chǎng)景使用了本地的環(huán)境來(lái)調(diào)用controller,你也可以多加上一些屬性接著執(zhí)行一個(gè)方法清除這些屬性,然后再驗(yàn)證一下屬性到底有沒(méi)有被清除。

#p#

$httpBackendIs Cool

那么要是你在調(diào)用$httpservice請(qǐng)求或是發(fā)送數(shù)據(jù)到服務(wù)端呢?還好,Angular提供了一種

$httpBackend的mock方法。這樣的話,你就能自定義服務(wù)端的響應(yīng)內(nèi)容,又或是確保服務(wù)端的響應(yīng)結(jié)果能和單元測(cè)試中的預(yù)期保持一致。

具體細(xì)節(jié)如下:

 
 
 
 
  1. describe('MainCtrl', function() { 
  2.     var $scope, $rootScope, $httpBackend, $timeout, createController; 
  3.     beforeEach(inject(function($injector) { 
  4.         $timeout = $injector.get('$timeout'); 
  5.         $httpBackend = $injector.get('$httpBackend'); 
  6.         $rootScope = $injector.get('$rootScope'); 
  7.         $scope = $rootScope.$new(); 
  8.  
  9.  
  10.         var $controller = $injector.get('$controller'); 
  11.  
  12.         createController = function() { 
  13.             return $controller('MainCtrl', { 
  14.                 '$scope': $scope 
  15.             }); 
  16.         }; 
  17.     })); 
  18.  
  19.     afterEach(function() { 
  20.         $httpBackend.verifyNoOutstandingExpectation(); 
  21.         $httpBackend.verifyNoOutstandingRequest(); 
  22.     }); 
  23.  
  24.     it('should run the Test to get the link data from the go backend', function() { 
  25.         var controller = createController(); 
  26.         $scope.urlToScrape = 'success.com'; 
  27.  
  28.         $httpBackend.expect('GET', '/slurp?urlToScrape=http:%2F%2Fsuccess.com') 
  29.             .respond({ 
  30.                 "success": true, 
  31.                 "links": ["http://www.google.com", "http://angularjs.org", "http://amazon.com"] 
  32.             }); 
  33.  
  34.         // have to use $apply to trigger the $digest which will 
  35.         // take care of the HTTP request 
  36.         $scope.$apply(function() { 
  37.             $scope.runTest(); 
  38.         }); 
  39.  
  40.         expect($scope.parseOriginalUrlStatus).toEqual('calling'); 
  41.  
  42.         $httpBackend.flush(); 
  43.  
  44.         expect($scope.retrievedUrls).toEqual(["http://www.google.com", "http://angularjs.org", "http://amazon.com"]); 
  45.         expect($scope.parseOriginalUrlStatus).toEqual('waiting'); 
  46.         expect($scope.doneScrapingOriginalUrl).toEqual(true); 
  47.     }); 
  48. }); 

正如你所見(jiàn),beforeEach call其實(shí)都很類似,唯一不同的是我們是從injector獲取$httpBackend而并非直接獲取。即使如此,創(chuàng)建不同的測(cè)試時(shí)還會(huì)有一些明顯的 不同之處。對(duì)初學(xué)者來(lái)說(shuō),會(huì)有一個(gè)afterEachcall 方法來(lái)確保$httpBackend在每次用例執(zhí)行后不會(huì)有明顯的異常請(qǐng)求。如果你觀察一下測(cè)試場(chǎng)景的設(shè)置和$httpBackend方法的應(yīng)用就會(huì)會(huì)發(fā) 現(xiàn)有那么幾點(diǎn)不是那么直觀的。

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

接下來(lái)的幾行代碼都是在調(diào)用過(guò)程中檢測(cè)$scopethat屬性的斷言。很酷吧?

提示:在某些單元測(cè)試中,用戶習(xí)慣把沒(méi)有$的范圍標(biāo)記為變量。這個(gè)在Angular文檔中并沒(méi)有強(qiáng)制要求或是過(guò)分強(qiáng)調(diào),只是我在使用中為了提高可讀性和一致性才使用$scopelike這種方式。

結(jié)論

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


文章名稱:如何在AngularJS中對(duì)控制器進(jìn)行單元測(cè)試
網(wǎng)站網(wǎng)址:http://www.5511xx.com/article/dhojsse.html