2015-03-02 118 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