[英]Jasmine test for Angular service does not resolve deferred call
I'm pretty new to Angular and I am working to test an Angular service that runs off an API level service which wraps a bunch of calls to a REST service. 我是Angular的新手,我正在测试一个运行API级别服务的Angular服务,该服务将大量调用包装到REST服务中。 Because it is working with HTTP requests, both parts of the service are working with promises and it seems to work fine, but I am having trouble getting any tests of promised behaviour working.
因为它正在处理HTTP请求,所以服务的两个部分都在使用promises,它似乎工作正常,但我无法对承诺的行为进行任何测试。
The relevant part of my service code ( grossly simplified ) looks like this: 我的服务代码的相关部分(非常简化)如下所示:
angular.module('my.info')
.service('myInfoService', function (infoApi, $q) {
infoLoaded: false,
allInfo: [],
getInfo: function () {
var defer = $q.defer();
if (infoLoaded) {
defer.resolve(allInfo);
} else {
infoApi.getAllInfo().then(function (newInfo) {
allInfo = newInfo;
infoLoaded = true;
defer.resolve(allInfo);
});
}
return defer.promise;
}
});
When I am setting up my mock I have something like this: 当我设置我的模拟时,我有这样的事情:
describe("Info Service ",
function() {
var infoService, infoRequestApi, $q;
beforeEach(module("my.info"));
beforeEach(function() {
module(function($provide) {
infoRequestApi = {
requestCount: 0,
getAllInfo: function() {
var defer = $q.defer();
this.requestCount++;
defer.resolve( [ "info 1", "info 2" ] );
return defer.promise;
}
};
$provide.value("infoApi", infoRequestApi);
});
inject(function( _myInfoService_, _$q_ ) {
infoService = _myInfoService_,
$q = _$q_;
});
});
it("should not fail in the middle of a test", function(done) {
infoService.getInfo().then( function(infoResult) {
// expectation checks.
expect( true ).toBeTrue();
}).finally(done);
});
});
Any synchronous tests pass fine, but when I try to run any tests like this I get a message saying: Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
任何同步测试都没有通过,但是当我尝试运行这样的任何测试时,我收到一条消息:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
It seems as though something about the way that Angular.Mocks handles the deferred result is causing it to fail. 看起来Angular.Mocks处理延迟结果的方式似乎导致它失败。 When I step through the test, the mock object's
defer
variable is being set correctly, but the then
statement in the service is never called. 当我逐步完成测试时,正确设置了模拟对象的
defer
变量,但从不调用服务中的then
语句。 Where am I going wrong? 我哪里错了?
Short Answer 简答
You have to kick off a digest cycle. 你必须开始一个消化周期。 You can do that with
$rootScope.$apply()
. 你可以用
$rootScope.$apply()
来做到这一点。
it("should not fail in the middle of a test", inject(function($rootScope) {
var actualResult = null;
infoService.getInfo()
.then(function(infoResult) { actualResult = infoResult; });
$rootScope.$apply();
expect(actualResult).toEqual(["info 1", "info 2"]);
}));
Note 注意
I wouldn't try to create a fake infoRequestApi
service the way you are doing it. 我不会尝试按照你的方式创建一个假的
infoRequestApi
服务。 You should be injecting that service as well, and spying on its functions. 您也应该注入该服务,并监视其功能。 For instance, something like this:
例如,像这样:
it("should not fail in the middle of a test", inject(function($rootScope, infoApi, $q) {
var deferred = $q.defer();
spyOn(infoApi, 'getAllInfo').and.returnValue(deferred.promise);
var actualResult = null;
var expectedResult = ["info 1", "info 2"];
infoService.getInfo()
.then(function(infoResult) { actualResult = infoResult; });
deferred.resolve(expectedResult);
$rootScope.$apply();
expect(actualResult).toBe(expectedResult);
}));
Refactored 重构
Also, your code can be simplified a bit ( untested, but close to what I would expect to see ). 此外,您的代码可以简化一点( 未经测试,但接近我期望看到的 )。
angular.module('my.info')
.service('myInfoService', function (infoApi, $q) {
return {
infoLoaded: false,
allInfo: [],
getInfo: function () {
var self = this;
return this.infoLoaded ? $q.resolve(this.allInfo) :
infoApi.getAllInfo().then(function (newInfo) {
self.allInfo = newInfo;
self.infoLoaded = true;
});
}
};
});
describe("Info Service ", function() {
var infoService, infoApi, $q, $rootScope;
beforeEach(module("my.info"));
beforeEach(inject(function( _myInfoService_, _$q_ _$rootScope_, _infoApi_) {
infoService = _myInfoService_,
$q = _$q_;
$rootScope = _$rootScope_;
infoApi = _infoApi_;
});
it("should do something", function() { // update message
var deferred = $q.defer();
spyOn(infoApi, 'getAllInfo').and.returnValue(deferred.promise);
var actualResult = null;
var expectedResult = ["info 1", "info 2"];
infoService.getInfo()
.then(function(infoResult) { actualResult = infoResult; });
deferred.resolve(expectedResult);
$rootScope.$apply();
expect(actualResult).toBe(expectedResult);
});
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.