如果您正在使用$ 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');
});
});
});
});
});
});
});
答案 0 :(得分:5)
此失败的原因是 - 尽管代码似乎是同步内部$q
使用$evalAsync
中的$scope
将工作推迟到将来的调用堆栈。由于$q
没有像flush
,$httpBackend
和$timeout
这样的$interval
方法,因此需要调用$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');
});
});
});
});
});
});
});