简体   繁体   English

在业力/茉莉花测试中模拟角度服务/承诺

[英]mock angular service/promise in a karma/jasmine test

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);

    ...

Here is how my service is : 以下是我的服务方式:

(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();
});
});

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) 我真正想做的是让我的响应对象({“elements:...})作为fillMapDatas函数的datas参数。我不明白如何模拟所有服务事物(服务,承诺,然后)

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]
    }
  });
}));

As you can see, you don't need to use $injector , since you can inject your needed services directly. 如您所见,您不需要使用$injector ,因为您可以直接注入所需的服务。 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. 如果您想在整个测试过程中使用正确的服务名称,可以使用前缀和后缀“_”注入它们, inject()足够聪明,可以识别您的意思。 We also setup the $httpBackend mock for each it() spec. 我们还为每个it()规范设置了$httpBackend模拟。 And we set up $q and $rootScope for later processing. 我们设置$q$rootScope以便以后处理。

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();
});

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). 由于promise始终具有.then()方法,因此我们可以检查此属性以查看它是否为promise(当然,其他对象也可以使用此方法)。

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. 您可以设置您明确解决的deferred

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]);
});

Hope this helps! 希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM