在业力/茉莉花测试中模拟角度服务/承诺 [英] mock angular service/promise in a karma/jasmine test
问题描述
我正在尝试编写一个 karma/jasmine 测试,我想要一些关于模拟如何在返回承诺的服务上工作的解释.我解释一下我的情况:
I'm trying to write a karma/jasmine test and I would like some explanations about how mocks are working on a service which is returning a promise. I explain my situation :
我有一个控制器,我在其中执行以下调用:
I have a controller in which I do the following call :
mapService.getMapByUuid(mapUUID, isEditor).then(function(datas){
fillMapDatas(datas);
});
function fillMapDatas(datas){
if($scope.elements === undefined){
$scope.elements = [];
}
//Here while debugging my unit test, 'datas' contain the promise javascript object instead //of my real reponse.
debugger;
var allOfThem = _.union($scope.elements, datas.elements);
...
以下是我的服务:
(function () {
'use strict';
var serviceId = 'mapService';
angular.module('onmap.map-module.services').factory(serviceId, [
'$resource',
'appContext',
'restHello',
'restMap',
serviceFunc]);
function serviceFunc($resource, appContext, restHello, restMap) {
var Maps = $resource(appContext+restMap, {uuid: '@uuid', editor: '@editor'});
return{
getMapByUuid: function (uuid, modeEditor) {
var maps = Maps.get({'uuid' : uuid, 'editor': modeEditor});
return maps.$promise;
}
};
}
})();
最后,这是我的单元测试:
And finally, here is my unit test :
describe('Map controller', function() {
var $scope, $rootScope, $httpBackend, $timeout, createController, MapService, $resource;
beforeEach(module('onmapApp'));
beforeEach(inject(function($injector) {
$httpBackend = $injector.get('$httpBackend');
$rootScope = $injector.get('$rootScope');
$scope = $rootScope.$new();
var $controller = $injector.get('$controller');
createController = function() {
return $controller('maps.ctrl', {
'$scope': $scope
});
};
}));
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
var response = {"elements":[1,2,3]};
it('should allow user to get a map', function() {
var controller = createController();
$httpBackend.expect('GET', '/onmap/rest/map/MY-UUID?editor=true')
.respond({
"success": response
});
// hope to call /onmap/rest/map/MY-UUID?editor=true url and hope to have response as the fillMapDatas parameter
$scope.getMapByUUID('MY-UUID', true);
$httpBackend.flush();
});
});
我真正想做的是将我的响应对象({元素:...})作为 fillMapDatas 函数的 datas 参数.我不明白如何模拟所有服务的东西(服务,承诺, 然后)
What I really want to do is to have my response object ( {"elements:...}) as the datas parameter of the fillMapDatas function. I don't understand how to mock all the service things (service, promise, then)
推荐答案
所以您想测试一下您的服务是否按预期响应?然后,这是您更愿意在服务上测试的内容.基于单元测试承诺的方法可能如下所示:
So you want to test, if your service responses as expected? Then, this is something you would rather test on the service. Unit test promise based methods could look like this:
var mapService, $httpBackend, $q, $rootScope;
beforeEach(inject(function (_mapService_, _$httpBackend_, _$q_, _$rootScope_) {
mapService = mapService;
$httpBackend = _$httpBackend_;
$q = _$q_;
$rootScope = _$rootScope_;
// expect the actual request
$httpBackend.expect('GET', '/onmap/rest/map/uuid?editor=true');
// react on that request
$httpBackend.whenGET('/onmap/rest/map/uuid?editor=true').respond({
success: {
elements: [1, 2, 3]
}
});
}));
如您所见,您不需要使用 $injector
,因为您可以直接注入所需的服务.如果您想在整个测试中使用正确的服务名称,您可以使用前缀和后缀_"来注入它们,inject()
足够聪明,可以识别您所指的服务.我们还为每个 it()
规范设置了 $httpBackend
模拟.并且我们设置了 $q
和 $rootScope
供以后处理.
As you can see, you don't need to use $injector
, since you can inject your needed services directly. If you wanna use the correct service names throughout your tests, you can inject them with prefixed and suffixed "_", inject()
is smart enough to recognise which service you mean. We also setup the $httpBackend
mock for each it()
spec. And we set up $q
and $rootScope
for later processing.
以下是测试服务方法是否返回承诺的方法:
Here's how you could test that your service method returns a promise:
it('should return a promise', function () {
expect(mapService.getMapUuid('uuid', true).then).toBeDefined();
});
由于promise 总是有一个.then()
方法,我们可以检查这个属性来看看它是否是promise 的(当然,其他对象也可以有这个方法).
Since a promise always has a .then()
method, we can check for this property to see if it's a promise or not (of course, other objects could have this method too).
接下来,您可以使用适当的值测试您获得的承诺.您可以设置一个您明确解析的 deferred
.
Next you can test of the promise you get resolves with the proper value. You can do that setting up a deferred
that you explicitly resolve.
it('should resolve with [something]', function () {
var data;
// set up a deferred
var deferred = $q.defer();
// get promise reference
var promise = deferred.promise;
// set up promise resolve callback
promise.then(function (response) {
data = response.success;
});
mapService.getMapUuid('uuid', true).then(function(response) {
// resolve our deferred with the response when it returns
deferred.resolve(response);
});
// force `$digest` to resolve/reject deferreds
$rootScope.$digest();
// make your actual test
expect(data).toEqual([something]);
});
希望这会有所帮助!
这篇关于在业力/茉莉花测试中模拟角度服务/承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!