如何模拟在 AngularJS Jasmine 单元测试中返回承诺的服务? [英] How do I mock a service that returns promise in AngularJS Jasmine unit test?
问题描述
我有使用 myOtherService
的 myService
,它进行远程调用,返回承诺:
I have myService
that uses myOtherService
, which makes a remote call, returning promise:
angular.module('app.myService', ['app.myOtherService'])
.factory('myService', [
myOtherService,
function(myOtherService) {
function makeRemoteCall() {
return myOtherService.makeRemoteCallReturningPromise();
}
return {
makeRemoteCall: makeRemoteCall
};
}
])
要对 myService
进行单元测试,我需要模拟 myOtherService
,使其 makeRemoteCallReturningPromise
方法返回一个承诺.我是这样做的:
To make a unit test for myService
I need to mock myOtherService
, such that its makeRemoteCallReturningPromise
method returns a promise. This is how I do it:
describe('Testing remote call returning promise', function() {
var myService;
var myOtherServiceMock = {};
beforeEach(module('app.myService'));
// I have to inject mock when calling module(),
// and module() should come before any inject()
beforeEach(module(function ($provide) {
$provide.value('myOtherService', myOtherServiceMock);
}));
// However, in order to properly construct my mock
// I need $q, which can give me a promise
beforeEach(inject(function(_myService_, $q){
myService = _myService_;
myOtherServiceMock = {
makeRemoteCallReturningPromise: function() {
var deferred = $q.defer();
deferred.resolve('Remote call result');
return deferred.promise;
}
};
}
// Here the value of myOtherServiceMock is not
// updated, and it is still {}
it('can do remote call', inject(function() {
myService.makeRemoteCall() // Error: makeRemoteCall() is not defined on {}
.then(function() {
console.log('Success');
});
}));
从上面可以看出,我的模拟的定义取决于 $q
,我必须使用 inject()
加载它.此外,注入模拟应该发生在 module()
中,它应该在 inject()
之前出现.但是,一旦我更改它,模拟的值就不会更新.
As you can see from the above, the definition of my mock depends on $q
, which I have to load using inject()
. Furthermore, injecting the mock should be happening in module()
, which should be coming before inject()
. However, the value for the mock is not updated once I change it.
这样做的正确方法是什么?
What is the proper way to do this?
推荐答案
我不知道为什么你的方法不起作用,但我通常使用 spyOn
函数来完成.像这样:
I'm not sure why the way you did it doesn't work, but I usually do it with the spyOn
function. Something like this:
describe('Testing remote call returning promise', function() {
var myService;
beforeEach(module('app.myService'));
beforeEach(inject( function(_myService_, myOtherService, $q){
myService = _myService_;
spyOn(myOtherService, "makeRemoteCallReturningPromise").and.callFake(function() {
var deferred = $q.defer();
deferred.resolve('Remote call result');
return deferred.promise;
});
}
it('can do remote call', inject(function() {
myService.makeRemoteCall()
.then(function() {
console.log('Success');
});
}));
还请记住,您需要调用 $digest
来调用 then
函数.请参阅$q 文档的测试部分.
Also remember that you will need to make a $digest
call for the then
function to be called. See the Testing section of the $q documentation.
------编辑------
仔细查看您正在做的事情后,我想我在您的代码中看到了问题.在 beforeEach
中,您将 myOtherServiceMock
设置为一个全新的对象.$provide
永远不会看到这个引用.您只需要更新现有的参考:
After looking closer at what you're doing, I think I see the problem in your code. In the beforeEach
, you're setting myOtherServiceMock
to a whole new object. The $provide
will never see this reference. You just need to update the existing reference:
beforeEach(inject( function(_myService_, $q){
myService = _myService_;
myOtherServiceMock.makeRemoteCallReturningPromise = function() {
var deferred = $q.defer();
deferred.resolve('Remote call result');
return deferred.promise;
};
}
这篇关于如何模拟在 AngularJS Jasmine 单元测试中返回承诺的服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!