2017-01-17 3 views
0

У меня есть служба под названием myHttp, которая возвращает обещание и контроллер, который вызывает myHttp дважды с различными параметрами.Тестирование двух разрешенных обещаний с помощью Angular/Jasmine

Чтобы проверить контроллер, я пытаюсь издеваться myHttp с Жасмин spyOn так:

beforeEach(inject(function($controller, _$rootScope_, _$q_, myHttp) { 
    $scope = _$rootScope_.$new(); 
    $q = _$q_; 
    deferred = $q.defer(); 
    deferred2 = $q.defer(); 
    spyOn(myHttp, 'call').and.callFake(fake(1)).and.returnValue(deferred.promise); 
    spyOn(myHttp, 'call').and.callFake(fake(2)).and.returnValue(deferred2.promise); 

где fake это функция, которая извлекает параметры, которые будут использоваться в myHttp вызова.

Проблема в том, что я не могу объявить дважды такую ​​же издеваемую функцию. Я получаю следующую ошибку от Жасмина:

Error: call has already been spied upon

Как можно проверить этот тест? это PLUNK

Javascript:

angular.module("mymodule", []) 

.service('myHttp', function($http,$q){ 
    this.call = function(obj) { 
     var defer = $q.defer(); 
     $http({url:obj.url, data:obj.data}) 
       .then(function (response) { 
        defer.resolve(response); 
       }); 
     return defer.promise; 
    }; 
}) 

.controller('ctl', function($scope,myHttp) { 
     $scope.read = function (id){ 
      var data = {}; 
      data.id = id; 
      myHttp.call({url:'/getStudent', data:data}) 
       .then(function(response) { 
        $scope.id = response.id; 
        $scope.name = response.nm; 
        $scope.classId = response.clsid; 

        var data2 = {}; 
        data2.id = $scope.classId; 
        myHttp.call({url:'/getClass', data:data2}) 
         .then(function(response) { 
          $scope.className = response.nm; 
        }); 
       }); 
    }; 
}); 



describe('Testing a Controller that uses a Promise', function() { 
    var $scope; 
    var $q; 
    var deferred; 
    var $timeout; 

    beforeEach(module('mymodule')); 

    beforeEach(inject(function($controller, _$rootScope_, _$q_, myHttp) { 
    $scope = _$rootScope_.$new(); 
    $q = _$q_; 
    deferred = $q.defer(); 
    deferred2 = $q.defer(); 
    spyOn(myHttp, 'call').and.callFake(fake(1)).and.returnValue(deferred.promise); 
    spyOn(myHttp, 'call').and.callFake(fake(2)).and.returnValue(deferred2.promise); 

    $controller('ctl', { 
     $scope: $scope, 
     myHttp: myHttp 
    }); 

    $scope.read(1) 

    })); 

    function fake (option) { 
    if (option==1) 
     return {url:'/getStudent', data: {id: 1}}; 
    else 
     return {url:'/getClass', data: {id: 10}}; 
    } 

    it('should resolve two promises', function() { 

    var student = { 
     id: 1, 
     nm: "John", 
     clsid: 10 
    }; 

    var clazz = { 
     id: 10, 
     nm: "Math" 
    }; 

    deferred.resolve(student); 
    $scope.$apply(); 

    deferred2.resolve(clazz); 
    $scope.$apply(); 

    expect($scope.id).toBe(student.id); 
    expect($scope.name).toBe(student.nm); 
    expect($scope.classId).toBe(student.clsid); 
    expect($scope.className).toBe(clazz.nm); 
    }); 

}); 

ответ

1

Просто шпионить myHttp.call один раз и изменить свой вызов поддельной функции, чтобы принять в параметрах запроса и возвращает объект на основе запроса.

var student = { 
    id: 1, 
    nm: "John", 
    clsid: 10 
}; 

var clazz = { 
    id: 10, 
    nm: "Math" 
}; 

spyOn(myHttp, 'call').and.callFake(function(obj) { 
    if (obj.url == '/getStudent') { 
    return $q.when(student); 
    } else if (obj.url = '/getClass') { 
    return $q.when(clazz); 
    } 
    return $q.reject('Mock not supported'); 
}); 

См. plunker для полного рабочего примера.

И как сторона, ваш HTTP вызов будет сведен к

.service('myHttp', function($http,$q){ 
    this.call = function(obj) { 
     return $http({url:obj.url, data:obj.data}); 
    }; 
}) 

потому $http уже возвращает обещание.

Кроме того, вы можете использовать угловой $httpBackend, чтобы высмеивать ваши http-вызовы вместо использования спам-жасмина. См. this plunker, который использует $httpBackend с небольшим изменением на myHttp.call.

0

Самый общий ответ на то, что вам не нужно, чтобы создать свой шпион на высшем уровне beforeEach. Вы можете использовать beforeEach, который ближе к отдельной спецификации или даже создает шпион в его заявлении. Вы также можете проверить что-то в своей подделке, чтобы узнать, какое обещание вы хотите вернуть, на основе параметра, с которым вызывается фальшивка.

Однако, какое условие вы действительно хотите проверить? Обычно есть что-то, что должно произойти после того, как обещание будет разрешено, и вы действительно хотите посмотреть на это. Легче дать вам конкретную обратную связь, если вы скажете, на что именно вы нацелены, в конце концов, вместо того, чтобы говорить, что вы считаете правильным решением, и спрашиваете нас, как добраться до этого.

Смотрите также $q.defer: You're doing it wrong