Angularjs 使用Jasmine测试立即解析$.defer()
如果您在Angular中测试代码,它使用$q并立即解析如下:Angularjs 使用Jasmine测试立即解析$.defer(),angularjs,jasmine,promise,synchronous,Angularjs,Jasmine,Promise,Synchronous,如果您在Angular中测试代码,它使用$q并立即解析如下: angular.module('MyApp.myModule', ['ng']) .service('someService', function($q) { this.task = function() { var deferred = $q.defer(); deferred.resolve('some value'); return deferred.promise; };
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');
});
});
});
});
});
});
});
失败的原因是,尽管代码在内部似乎是同步的,
$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');
});
});
});
});
});
});
});