2014-04-24 2 views
2

으로 해결했습니다. $ q를 사용하는 Angular 코드를 테스트하는 경우 다음과 같이 즉시 해결됩니다.

angular.module('MyApp.myModule', ['ng']) 
    .service('someService', function($q) { 
    this.task = function() { 
     var deferred = $q.defer(); 
     deferred.resolve('some value'); 
     return deferred.promise; 
    }; 
    }); 

다음과 같이 사용할 수 있습니다.

function(someService) { 
    someService.task().then(function() { 
    console.log('resolved'); 
    }); 
} 

응용 프로그램에서 예상대로 실행되지만 테스트에서는 실패 할 수 있습니다.

PhantomJS 1.9.7 (Mac OS X) MyApp.myModule someService someService.task when invoked returned promise when invoked should call our handler immediately FAILED 
    Expected spy onTaskComplete to have been called with [ 'some value' ] but it was never called. 

위의 모듈에 대한 예제 테스트입니다. 이것이 실패

describe('MyApp.myModule', function() { 
    describe('someService', function() { 
    beforeEach(function() { 
     var suite = this; 
     module('MyApp.myModule'); 
     suite.injectService = function() { 
     inject(function(someService) { 
      suite.someService = someService; 
     }); 
     }; 
    }); 
    describe('when instantiated', function() { 
     beforeEach(function() { 
     this.injectService(); 
     }); 
     it('should expose the expected API', function() { 
     expect(typeof this.someService.task).toEqual('function'); 
     }); 
    }); 
    describe('someService.task', function() { 
     describe('when invoked', function() { 
     beforeEach(function() { 
      this.injectService(); 
      this.taskPromise = this.someService.task(); 
     }); 
     it('should return a promise', function() { 
      expect(typeof this.taskPromise.then).toEqual('function'); 
     }); 
     describe('returned promise', function() { 
      describe('when invoked', function() { 
      beforeEach(function() { 
       this.onTaskComplete = jasmine.createSpy('onTaskComplete'); 
       this.taskPromise.then(this.onTaskComplete); 
      }); 
      it('should call our handler immediately', function() { 
       expect(this.onTaskComplete).toHaveBeenCalledWith('some value'); 
      }); 
      }); 
     }); 
     }); 
    }); 
    }); 
}); 

답변

5

이유는 코드가 동기-내부적으로 $q이 미래의 호출 스택 때까지 작업을 연기 할 $scope에서 $evalAsync을 사용하는 것으로 보이지만 것을-이다. $q에는 $httpBackend, $timeout$interval과 같은 flush 메서드가 없으므로 동일한 결과를 얻으려면 $rootScope.$digest()을 호출해야합니다.

PhantomJS 1.9.7 (Mac OS X): Executed 3 of 3 SUCCESS (0.451 secs/0.01 secs) 

다음은 업데이트 된 예제 테스트입니다.

describe('MyApp.myModule', function() { 
    describe('someService', function() { 
    beforeEach(function() { 
     var suite = this; 
     module('MyApp.myModule'); 
     inject(function($rootScope) { 
     suite.$rootScope = $rootScope; 
     }); 
     suite.injectService = function() { 
     inject(function(someService) { 
      suite.someService = someService; 
     }); 
     }; 
    }); 
    describe('when instantiated', function() { 
     beforeEach(function() { 
     this.injectService(); 
     }); 
     it('should expose the expected API', function() { 
     expect(typeof this.someService.task).toEqual('function'); 
     }); 
    }); 
    describe('someService.task', function() { 
     describe('when invoked', function() { 
     beforeEach(function() { 
      this.injectService(); 
      this.taskPromise = this.someService.task(); 
     }); 
     it('should return a promise', function() { 
      expect(typeof this.taskPromise.then).toEqual('function'); 
     }); 
     describe('returned promise', function() { 
      describe('when invoked', function() { 
      beforeEach(function() { 
       this.onTaskComplete = jasmine.createSpy('onTaskComplete'); 
       this.taskPromise.then(this.onTaskComplete); 
       this.$rootScope.$digest(); 
      }); 
      it('should call our handler immediately', function() { 
       expect(this.onTaskComplete).toHaveBeenCalledWith('some value'); 
      }); 
      }); 
     }); 
     }); 
    }); 
    }); 
});