2015-01-06 3 views
2

У меня есть ресурс завод

angular.module('mean.clusters').factory('Clusters', ['$resource', 
    function($resource) { 
    return $resource('clusters/:clusterId/:action', { 
     clusterId: '@_id' 
    }, { 
     update: {method: 'PUT'}, 
     status: {method: 'GET', params: {action:'status'}} 
    }); 
}]); 

и контроллер

angular.module('mean.clusters').controller('ClustersController', ['$scope', 
    '$location', 'Clusters', 
    function ($scope, $location, Clusters) { 
     $scope.create = function() { 
      var cluster = new Clusters(); 

      cluster.$save(function (response) { 
       $location.path('clusters/' + response._id); 
      }); 
     }; 

     $scope.update = function() { 
      var cluster = $scope.cluster; 

      cluster.$update(function() { 
       $location.path('clusters/' + cluster._id); 
      }); 
     }; 


     $scope.find = function() { 
      Clusters.query(function (clusters) { 
       $scope.clusters = clusters; 

      }); 
     }; 
}]); 

Я пишу мои модульные тесты и каждый пример, который я найти используем некоторую форму $httpBackend.expect, чтобы высмеять ответ с сервера, и я могу сделать это просто отлично.

Мои проблемы в том, что когда модуль тестирует мои функции контроллера, я хотел бы высмеять объект Clusters. Если я использую $httpBackend.expect, и я ввожу ошибку на моем заводе, каждый модульный тест в моем контроллере не удастся.

Я хотел бы получить мой тест $scope.create только тест $scope.create, а не мой заводской код.

Я попытался добавить провайдера в часть моих тестов, но я не могу понять, как это правильно.

Я также попытался

clusterSpy = function (properties){ 
    for(var k in properties) 
     this[k]=properties[k]; 
}; 

clusterSpy.$save = jasmine.createSpy().and.callFake(function (cb) { 
    cb({_id: '1'}); 
}); 

и установка Clusters = clusterSpy; в before(inject но в функции создания, шпион потеряется с

Error: Expected a spy, but got Function.

Я был в состоянии получить объект шпиона работать на вызов cluster.$update, но затем он не работает с var cluster = new Clusters(); с ошибкой «не является функцией».

Я могу создать функцию, которая работает для var cluster = new Clusters();, но затем не подходит для вызовов типа cluster.$update.

Я, вероятно, смешиваю здесь термины, но есть ли подходящий способ издеваться над кластерами со шпионами над функциями или есть веская причина просто пойти с $httpBackend.expect?

ответ

3

Похоже, я был рядом несколько раз, но я думаю, что я понял это сейчас.

Решение было частью «Я также попробовал» выше, но я не возвращал объект-шпион из функции.

Это работает, он может быть помещен либо в beforeEach(module( или beforeEach(inject секций

Шаг 1: создать объект шпиона с любыми функциями, которые вы хотите проверить и присвоить его переменной, которая доступна для тестов.

Шаг 2: создайте функцию, которая возвращает объект-шпион.

Шаг 3: скопируйте свойства объекта-шпиона в новую функцию.

clusterSpy = jasmine.createSpyObj('Clusters', ['$save', 'update', 'status']); 

clusterSpyFunc = function() { 
    return clusterSpy 
}; 

for(var k in clusterSpy){ 
    clusterSpyFunc[k]=clusterSpy[k]; 
} 

Шаг 4: добавить его в $ контроллера в разделе beforeEach(inject.

ClustersController = $controller('ClustersController', { 
    $scope: scope, 
    Clusters: clusterSpyFunc 
}); 

внутри ваших тестов вы можете добавить функциональность к методам использования

clusterSpy.$save.and.callFake(function (cb) { 
    cb({_id: '1'}); 
}); 

затем проверить шпиона значения

expect(clusterSpy.$save).toHaveBeenCalled(); 

Это решает обе проблемы new Clusters() и Clusters.query не будучи функция. И теперь я могу выполнить тестирование моего контроллера с зависимостью от фабрики ресурсов.

0

Другой способ издеваться службы Кластеры это:

describe('Cluster Controller', function() { 

    var location, scope, controller, MockClusters, passPromise, q; 
    var cluster = {_id : '1'}; 

    beforeEach(function(){ 

     // since we are outside of angular.js framework, 
     // we inject the angujar.js services that we need later on 
     inject(function($rootScope, $controller, $q) { 
     scope = $rootScope.$new(); 
     controller = $controller; 
     q = $q; 
     }); 

     // let's mock the location service 
     location = {path: jasmine.createSpy('path')}; 

     // let's mock the Clusters service 
     var MockClusters = function(){}; 
     // since MockClusters is a function object (not literal object) 
     // we'll need to use the "prototype" property 
     // for adding methods to the object 
     MockClusters.prototype.$save = function(success, error) { 
     var deferred = q.defer(); 
     var promise = deferred.promise; 

     // since the Clusters controller expect the result to be 
     // sent back as a callback, we register the success and 
     // error callbacks with the promise 
     promise.then(success, error); 

     // conditionally resolve the promise so we can test 
     // both paths 
     if(passPromise){ 
      deferred.resolve(cluster); 
     } else { 
      deferred.reject(); 
     } 
     } 

     // import the module containing the Clusters controller 
     module('mean.clusters') 
     // create an instance of the controller we unit test 
     // using the services we mocked (except scope) 
     controller('ClustersController', { 
     $scope: scope, 
     $location: location, 
     Clusters: MockClusters 
     }); 


    it('save completes successfully', function() { 
     passPromise = true; 
     scope.save(); 

     // since MockClusters.$save contains a promise (e.g. an async call) 
     // we tell angular to process this async call before we can validate 
     // the response 
     scope.$apply(); 

     // we can call "toHaveBeenCalledWith" since we mocked "location.path" as a spy 
     expect(location.path).toHaveBeenCalledWith('clusters/' + cluster._id);); 

    }); 

    it('save doesn''t complete successfully', function() { 
     passPromise = false; 
     scope.save(); 

     // since MockClusters.$save contains a promise (e.g. an async call) 
     // we tell angular to process this async call before we can validate 
     // the response 
     scope.$apply(); 

     expect(location.path).toHaveBeenCalledWith('/error');); 

    }); 

    }); 

}); 
+0

Чтобы увидеть разницу между объектами функций и литералов объектов искать книгу «JavaScript: хороший части» от Дугласа Crockford, страницы 20-30. PDF-версию книги можно легко найти, выполнив поиск Google. – claudius

Смежные вопросы