我有一个像这样的
具有异步依赖的角度服务(function() {
angular
.module('app')
.factory('myService', ['$q', 'asyncService',
function($q, asyncService) {
var myData = null;
return {
initialize: initialize,
};
function initialize(loanId){
return asyncService.getData(id)
.then(function(data){
console.log("got the data!");
myData = data;
});
}
}]);
})();
我想对initialize
函数进行单元测试,我正在尝试像这样的茉莉:
describe("Rate Structure Lookup Service", function() {
var $q;
var $rootScope;
var getDataDeferred;
var mockAsyncService;
var service;
beforeEach(function(){
module('app');
module(function ($provide) {
$provide.value('asyncService', mockAsyncService);
});
inject(function(_$q_, _$rootScope_, myService) {
$q = _$q_;
$rootScope = _$rootScope_;
service = myService;
});
getDataDeferred = $q.defer();
mockAsyncService = {
getData: jasmine.createSpy('getData').and.returnValue(getDataDeferred.promise)
};
});
describe("Lookup Data", function(){
var data;
beforeEach(function(){
testData = [{
recordId: 2,
effectiveDate: moment("1/1/2015", "l")
},{
recordId: 1,
effectiveDate: moment("1/1/2014", "l")
}];
});
it("should get data", function(){
getDataDeferred.resolve(testData);
service.initialize(1234).then(function(){
console.log("I've been resolved!");
expect(mockAsyncService.getData).toHaveBeenCalledWith(1234);
});
$rootScope.$apply();
});
});
});
没有任何控制台消息出现,测试似乎只是在没有承诺得到解决的情况下继续进行。我虽然$rootScope.$apply()
会这样做,但似乎没有。
更新
@estus是对的,$rootScope.$appy()
足以触发所有承诺的解决。似乎问题出在我对asyncService的模拟中。我从
mockAsyncService = {
getData: jasmine.createSpy('getData').and.returnValue(getDataDeferred.promise)
};
到
mockAsyncService = {
getData: jasmine.createSpy('getData').and.callFake(
function(id){
return $q.when(testData);
})
};
我将testData
设置为测试所需的内容,而不是调用getDataDeferred.resolve(testData)
。在此更改之前,正在注入mockAsyncService,但getDataDeferred
的承诺从未得到解决。
我不知道这是beforeEach
中的注射顺序还是什么。更奇怪的是,这必须是callFake
。使用.and.returnValue($q.when(testData))
仍会阻止承诺解析。
答案 0 :(得分:6)
角度承诺在测试期间是同步的,$rootScope.$apply()
足以使它们在规范的最后得到解决。
除非asyncService.getData
返回真正的承诺而不是$q
承诺(在这种情况下它不会),否则异步性在Jasmine中不是问题。
Jasmine promise matchers库非常适合测试Angular promise。除了明显缺乏冗长之外,它还在这种情况下提供了有价值的反馈。虽然这个
rejectedPromise.then((result) => {
expect(result).toBe(true);
});
如果没有,那么规范就会通过
expect(pendingPromise).toBeResolved();
expect(rejectedPromise).toBeResolvedWith(true);
会因有意义的消息而失败。
测试代码的实际问题在beforeEach
中是优先的。角度自举过程不是同步的。
getDataDeferred = $q.defer()
应该放入inject
块,否则它将在模块被引导并注入$q
之前执行。
使用mockAsyncService
的问题getDataDeferred.promise
也是如此。
在最佳情况下,代码会抛出错误,因为在defer
上调用了undefined
方法。在最坏的情况下(这就是为什么像[{1}}这样的规范属性比本地套件变量更可取的原因)this.$q
属于前一个规范的注入器,因此$q
将没有效果在这里。
答案 1 :(得分:4)
您需要将可选的done参数传递给it块中的回调函数。否则jasmine无法知道你正在测试异步函数 - 异步函数会立即返回。
这是重构:
"from __main__ import heap1, heap2; test_list = %r" % test_list
答案 2 :(得分:0)
这里有一些(片状,啤酒垫)指针。不幸的是,我无法知道它们是否是真正的错误,或者它们是否是“错别字”#34;因为你"简化"代码。
首先,没有理由不提供asyncService作为服务和内联。试试这个:
$provide.service('asyncService', function() {
// asyncService implementation
});
另外,我不相信这种依赖注入会起作用。
inject(function(_$q_, _$rootScope_, myService) {
$q = _$q_;
$rootScope = _$rootScope_;
service = myService;
});
因为DI容器不了解myServiceProvider。你可以试试这个:
inject(function(_$q_, _$rootScope_, _asyncService_) {
$q = _$q_;
$rootScope = _$rootScope_;
service = _asyncService_;
});
哪种方法有效,因为您之前使用' asyncService'作为参数。
此外,您还没有正确使用$ promise api。您未在单元测试中向.then()返回resolve()&#d承诺。尝试使用asyncService的替代实现,类似于:
$provide.service('asyncService', function() {
this.getData = function() {
return $q(function(resolve, reject) {
resolve('Promise resolved');
});
}
});
你可以在你的单元测试中监视这个。没有理由在beforeEach()函数中调用间谍。
jasmine.spyOn(service, 'getData').and.callThrough();
你的期望()看起来不错。
如果有任何问题可以帮助我。