在业力/茉莉花测试中模拟角度服务/承诺 [英] mock angular service/promise in a karma/jasmine test

查看:23
本文介绍了在业力/茉莉花测试中模拟角度服务/承诺的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆