2015-03-02 115 views
1

內懲戒與承諾服務,爲測試我有以下服務(降低爲簡單起見):其他服務

angular.module('myApp') 
    .factory('BasicTimerService', function BasicTimerService(PromiseService) 
    { 
     var isPlaying = false, 
      maxEventTime = 0; 

     return { 
      start: function() 
      { 
       // only "start" once this promise has resolved. 
       PromiseService.get_promise() 
        .then(function(value) 
        { 
         maxEventTime = PromiseService.maxEventTime(); 
         isPlaying = true; 
        }); 
      }, 
      get_isPlaying: function() { 
       return isPlaying; 
      } 
     }; 
    }); 

我想測試maxEventTime只設置後,承諾是成功的。

我的測試:

describe('Service: BasicTimerService', function() { 
    beforeEach(module('myApp')); 

    var mockPromiseService, 
     BasicTimerService, 
     $q, 
     $rootScope, 
     deferred; 

    beforeEach(function(){ 
     mockPromiseService = { 
      maxEventTime: function() { 
       return 17000; 
      } 
     }; 

     module(function($provide){ 
      $provide.value('PromiseService', mockPromiseService); 
     }); 

     inject(function(_BasicTimerService_, _$q_, _$rootScope_){ 
      BasicTimerService = _BasicTimerService_; 
      $rootScope = _$rootScope_; 
      $q = _$q_; 
     }); 

     mockPromiseService.get_promise = function() { 
      var deferred = $q.defer(); 
      deferred.resolve('hello world'); 
      return deferred.promise; 
     }; 
    }); 

    it('should get maxEventTime once the promise is resolved.', function() { 
     spyOn(mockPromiseService, 'get_promise').and.callThrough(); 
     spyOn(mockPromiseService, 'maxEventTime').and.callThrough(); 

     $rootScope.$apply(); 

     BasicTimerService.start(); 

     expect(mockPromiseService.get_promise).toHaveBeenCalled(); 
     expect(BasicTimerService.get_isPlaying()).toBe(true); 
     expect(mockPromiseService.maxEventTime).toHaveBeenCalled(); 
    }); 
}); 

我確定mockPromiseService.get_promise()調用成功(第一個想到()是成功的),但在BasicTimerService的。那麼()子句中似乎沒有被調用,我不明白爲什麼。

我已經嘗試使用$rootScope.$apply();以及$rootScope.$digest();無濟於事。

任何想法爲什麼這不起作用?

+3

從'start'返回承諾。作爲一個規則,如果某個東西執行I/O,它應該總是返回該Io完成的承諾(或者在回調版本中進行回調)。 – 2015-03-02 20:19:17

回答

2

您的start()方法是異步的,所以如果它工作正常,get_isPlaying()將不會是true到您檢查其值時。你需要等待結果(修改start()返回一個承諾本傑明Gruenbaum曾建議:

it('should get maxEventTime once the promise is resolved.', function(done) { 
    spyOn(mockPromiseService, 'get_promise').and.callThrough(); 
    spyOn(mockPromiseService, 'maxEventTime').and.callThrough(); 

    $rootScope.$apply(); 

    BasicTimerService.start().then(function() { 
     expect(mockPromiseService.get_promise).toHaveBeenCalled(); 
     expect(BasicTimerService.get_isPlaying()).toBe(true); 
     expect(mockPromiseService.maxEventTime).toHaveBeenCalled(); 
     done(); 
    }); 
}); 

你也不必在get_promise使用$q.defer()(你幾乎永遠不需要使用$q.defer()):

mockPromiseService.get_promise = function() { 
    return $q.when('hello world'); 
}; 

注:基於$q文檔,它看起來像你可以使用$rootScope.$apply()得到承諾價值觀傳播給他們的then處理程序,但我認爲你應該把承諾的承諾,並使用012的意見等進行測試。

+1

我不得不將$ rootScope.apply()移動到我測試的最後一行,但其他所有工作都如前所述。謝謝你的幫助! – 2015-03-03 13:57:55