2013-10-12 62 views
1

我目前正在瀏覽名爲「用AngularJS掌握Web應用程序開發」的書,並且在其中一個示例中有一個名爲「聚合回調」的測試。Angularjs和Jasmine:使用同一服務的多個實例進行測試

我已經得到了問題的例子包含Person對象:

var Person = function(name, $log) { 

    this.eat = function(food) { 

     $log.info(name + ' is eating delicious ' + food); 

    }; 

    this.beHungry = function(reason) { 

     $log.warn(name + ' is hungry because: ' + reason); 

    }; 

}; 

對象調用餐廳:

var Restaurant = function($q, $rootScope) { 

    var currentOrder; 

    return { 

     takeOrder : function(orderedItems) { 

      currentOrder = { 

       deferred : $q.defer(), 
       items : orderedItems 

      }; 

      return currentOrder.deferred.promise; 

     }, 

     deliverOrder : function() { 

      currentOrder.deferred.resolve(currentOrder.items); 
      $rootScope.$digest(); 

     }, 

     problemWithOrder : function(reason) { 

      currentOrder.deferred.reject(reason); 
      $rootScope.$digest(); 

     } 

    }; 

}; 

,最後的測試聚集回調:

it('should allow callbacks aggregation', function() { 

    var pizzaPid = new Restaurant($q, $rootScope); 

    var pizzaDelivered = pizzaPid.takeOrder('Margherita'); 

    pizzaDelivered.then(pawel.eat, pawel.beHungry); 
    pizzaDelivered.then(pete.eat, pete.beHungry); 

    pizzaPid.deliveryOrder(); 

    expect($log.info.logs).toContain(['Pawel is eating delicious Margherita']); 
    expect($log.info.logs).toContain(['Pete is eating delicious Margherita']); 

}); 

正如您所看到的,測試不會顯示項目是如何添加/注入測試的,一般來說,我對TDD的概念很陌生。

我已經結束了做什麼,以服務和工廠的全局對象轉換:

angular.module('myApp', []) 

    .service('Person', function(personName, $log) { 

     this.eat = function(food) { 

      $log.info(personName + ' is eating delicious ' + food); 

     }; 

     this.beHungry = function(reason) { 

      $log.warn(personName + ' is hungry because: ' + reason); 

     }; 

    }) 

    .factory('Restaurant', function($q, $rootScope) { 

     var currentOrder; 

     return { 

      takeOrder : function(orderedItems) { 

       currentOrder = { 

        deferred : $q.defer(), 
        items : orderedItems 

       }; 

       return currentOrder.deferred.promise; 

      }, 

      deliverOrder : function() { 

       currentOrder.deferred.resolve(currentOrder.items); 
       $rootScope.$digest(); 

      }, 

      problemWithOrder : function(reason) { 

       currentOrder.deferred.reject(reason); 
       $rootScope.$digest(); 

      } 

     }; 

    }); 

但現在我的服務的多個實例奮力代表「帕維爾」和「皮特'在我的測試中:

describe('Person and Restaurant tests', function() { 

    var Person; 
    var Restaurant; 

    var $q; 
    var $rootScope; 
    var $log; 




    beforeEach(function() { 


     module('myApp'); 

     module(function($provide) { 

      $provide.value('personName', 'Pawel'); 

     }); 

     inject(function(_Person_, _Restaurant_, _$q_, _$rootScope_, _$log_) { 

      Person = _Person_; 
      Restaurant = _Restaurant_; 

      $q = _$q_; 
      $rootScope = _$rootScope_; 
      $log = _$log_; 

     }); 



    }); 


    it('should allow callbacks aggregation', function() { 

     var pizzaDelivered = Restaurant.takeOrder('Margherita'); 

     // here's where the problem is 
     // with current set up I can only call it as 
     // pizzaDelivered.then(Person.eat, Person.beHungry);   
     pizzaDelivered.then(pawel.eat, pawel.beHungry); 
     pizzaDelivered.then(pete.eat, pete.beHungry); 

     Restaurant.deliveryOrder(); 

     expect($log.info.logs).toContain(['Pawel is eating delicious Margherita']); 
     expect($log.info.logs).toContain(['Pete is eating delicious Margherita']); 

    }); 


}); 

正如我所說 - 我是新來的,並希望得到一些幫助。

回答

1

之所以測試只允許

pizzaDelivered.then(Person.eat, Person.beHungry) 

是因爲你已經創建了一個人服務。在Angular中,服務是單身人士。 「人」的概念並不完全契合單身的概念,但可以在您的應用程序中,像這樣使用(也就是說,可在任何給定的時間超過1人):

app = app.module('app', []) 
    .controller('chicago', function($scope, $log) { 

     $scope.family = [ 
     new Person('henry', $log), 
     new Person('me', $log), 
     new Person('you', $log) 
     ]; 

    }); 

你應該將人員和餐廳作爲書中的定義。 我相信這是這本書的意圖,因爲 該定義中存在的唯一代碼行:

$rootScope.$digest(); 

http://docs.angularjs.org/guide/concepts 此行調用角的消化週期。它基本上貫穿所有角度,並通過其上下文中發生的任何更改來更新DOM和View。例如, 如果您的HTML有一個綁定到$範圍模式:

<div ng-model='name'> {{ name }} </div> 

後幾個HTTP調用到服務器之後,JS的角部位內這種模式的轉變,角度會自動更新此div有新的名字。 但是,如果代碼存在於角度上下文之外,則必須顯式調用$ digest,因爲角度在其上下文(其角度代碼)中不會意識到已更改的值。唯一可以明確調用$ digest()的時間在指令內,但大部分時間處理第三方代碼與angular的交互。

這將是我前進的建議:

許可的人,獨自餐廳代碼。不要將它們轉換成角度服務。 在聚集回調測試前beforeEach功能,實例2 Person對象

beforeEach(function() {  
    pete = new Person('pete', $log); 
    pawel = new Person('pawel', $log); 
}); 

一兩件事我注意到的是,你說,這本書的人與餐廳是全局對象,但他們不是。他們有全局函數/構造函數。

這應該讓你的測試通過。總的來說,我相信本書通過這個教給你的是使用angular以外的代碼。在許多真實世界的應用程序中,你幾乎不可能單獨使用角度js代碼。很多時候,你必須使用GoogleMaps,Moment等第三方代碼。

需要記住的未來: 我相信未來的角度版本(2.0),該項目標題爲進一步抽象$摘要循環並使用Observe()fn的方向。

+0

謝謝亞歷克斯 - 非常翔實 - 感謝您的幫助。 –

+0

然而,有一件事 - 你說上面定義的對象不是全局的 - 根據我的(有限的)理解,在任何其他對象之外的對象在javascript中的實例化 - 或者在這種情況下使用變量賦值在Angular之外創建一個對象全局命名空間。我不是在這裏嗎?你能解釋爲什麼你認爲:var Person = function(name,$ log){}不會創建一個全局對象嗎? –

+0

@SpencerMark你是對的,該人在全球名字空間。然而,Person是一個功能而不是一個對象。你讓我懷疑自己,因爲我對JS相當陌生:D – Alex

相關問題