Модульное тестирование службы angular.js (сервер node.js) в контроллере

Я новичок в модульном тестировании на стороне клиента. Мое приложение использует express.js, angularjs-ui-router и node.js. В настоящее время я начинаю писать тестовые примеры для приложения. Я использую Карма, Мокко, Чай, Синон для юнит-тестирования.

Мой конфиг роутера выглядит так:

$stateProvider
        .state('drive', {
            url: '/drive',
            templateUrl: 'drive.jade',
            controller: 'driveCtrl',
        });

контроллер:

 angular.module('mApp').controller('driveCtrl', ['$scope', 'driveService',
 function($scope, driveService) {
    var driveInfo = driveService.get({}, function() {});
    driveInfo.$promise.then(function(rs) {
            var drivers = [];
            //Logical operation
            $scope.drivers = drivers;
    });
}]);

Фабрика Ресурс:

mApp.factory('driveService', ['$resource', function($resource) {
      return $resource('/drive/id/:id/', {id:'@id'});
  }]);

DriveService - это фабрика, которая использует ресурсы angular.js $. Я пробовал различные варианты, но ничего не работает (используя $httpbackend, $q). Можете ли вы помочь мне написать способ тестирования контроллера, издеваясь над DriveService.

Вот мой код модульного теста:

var expect = require('chai').expect;
var sinon = require('sinon');

describe('Drive Service initialisation', function() {
    var scope, controller, state, $q, mockDriveService, driveServiceResponse = [{name:'james', type: 'heavy'}], queryDeferred;
    beforeEach(angular.mock.module('mApp'));

    angular.mock.module(function($provide){
            $provide.value('driveService', mockDriveService);
        });

    describe(' drive service called', function() {

      beforeEach(inject(function($controller, $rootScope, $state, _$q_, driveService) {
        $q = _$q_;  
        scope = $rootScope.$new(); 

        mockDriveService = {
            get:function(){
                queryDeferred = $q.defer();
                queryDeferred.resolve(driveServiceResponse);
                return {$promise: queryDeferred.promise};
            }
        };
        controller = $controller('driveCtrl', { $scope: scope, driveService:driveService}); 
        sinon.stub(mockDriveService, 'get');
        scope.$apply();
      }));

      it('expect filter to be empty', function () {
        expect(scope.drivers).to.not.be.empty;
      });

    });
  });

Ошибка, которую я получаю:

Error: Unexpected request: GET /driveService/id
No more request expected
    at $httpBackend (node_modules/angular-mocks/angular-mocks.js:1210:9)
    at sendReq (public/javascripts/lib/angular/angular.js:10333:9)
    at serverRequest (public/javascripts/lib/angular/angular.js:10045:16)
    at processQueue (public/javascripts/lib/angular/angular.js:14567:28)
    at public/javascripts/lib/angular/angular.js:14583:27
    at Scope.$eval (public/javascripts/lib/angular/angular.js:15846:28)
    at Scope.$digest (public/javascripts/lib/angular/angular.js:15657:31)
    at Scope.$apply (public/javascripts/lib/angular/angular.js:15951:24)
    at Context.<anonymous> (C:/Users/por/AppData/Local/Temp/b0475694b46e0d60262621ad126ce46c.browserify:63:9)
    at Object.invoke (public/javascripts/lib/angular/angular.js:4450:17)
Error: Declaration Location
    at window.inject.angular.mock.inject (node_modules/angular-mocks/angular-mocks.js:2375:25)

1 ответ

Вы определяете фиктивную службу, но по-прежнему предоставляете немодированную driveService для контроллера (это уже было сделано по умолчанию).

Дело в том, что driveService.get заглушается после того, как был создан экземпляр контроллера и вызван метод, не помогает в этом случае.

Это должно быть что-то вроде

    mockDriveService = {
        get: sinon.stub().returns({$promise: $q.resolve(driveServiceResponse)})
    };
    controller = $controller('driveCtrl', { $scope: scope, driveService:mockDriveService}); 
    scope.$apply();

Приложение должно иметь дружественный к тестированию дизайн для эффективного тестирования. Учитывая, что маршрутизатор загружен в модуль верхнего уровня и его конфигурация также определена там, модули приложения, которые должны быть проверены, должны быть определены в дочерних модулях, чтобы их можно было тестировать изолированно.

Приложение может быть переработано как

angular.module('mApp', ['ui.router', 'mApp.drive']);
...
angular.module('mApp.drive', [])
.controller('driveCtrl', ...)
.factory('driveService', ...);

И его единицы могут быть проверены как

beforeEach(angular.mock.module('mApp.drive'));
...
Другие вопросы по тегам