2016-08-11 2 views
0

Я пытаюсь выполнить тестирование моих состояний в контроллере. Что я хочу сделать, это закрыть мою фабрику items, так как у меня есть отдельные модульные тесты, которые охватывают эту функциональность. Мне тяжело получить $injector, чтобы на самом деле ввести завод, но похоже, что я даю $provider знать, что я хочу использовать объект поддельных объектов, когда он создает экземпляр контроллера. Как отказ от ответственности я совершенно новый для углового и хотел бы получить некоторые советы, если мой код выглядит плохо.Стабильная фабрика используется в разрешении

В настоящее время, когда я запускаю тест, который я получаю сообщение:

Error: Unexpected request: GET /home.html 
    No more request expected 
     at $httpBackend (node_modules/angular-mocks/angular-mocks.js:1418:9) 
     at n (node_modules/angular/angular.min.js:99:53) 
     at node_modules/angular/angular.min.js:96:262 
     at node_modules/angular/angular.min.js:131:20 
     at m.$eval (node_modules/angular/angular.min.js:145:347) 
     at m.$digest (node_modules/angular/angular.min.js:142:420) 
     at Object.<anonymous> (spec/states/homeSpec.js:29:16) 

Вероятно, что мой издевались элементы завод не вводят в тест. Когда я помещаю строку console.log в метод, который я хочу заглушить на фабрике элементов, я вижу, что эта строка вызывается.

Код я ищу, чтобы проверить это следующим образом:

angular.module('todo', ['ui.router']) 
// this is the factory i want to stub out... 
.factory('items', ['$http', function($http){ 
    var itemsFactory = {}; 
    itemsFactory.getAll = function() { 
    // ...specifically this method 
    }; 
    return itemsFactory; 
}]) 
.controller('TodoCtrl', ['$scope', 'items', function($scope, items) { 
    // Do things 
}]) 
.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider){ 
    $stateProvider 
    .state('home', { 
     url: '/home', 
     templateUrl: '/home.html', 
     controller: 'TodoCtrl', 
     resolve: { 
     items: ['items', function(items){ 
      // this is the invocation that i want to use my stubbed method 
      return items.getAll(); 
     }] 
     } 
    }); 

    $urlRouterProvider.otherwise('home'); 
}]); 

Мой тест выглядит следующим образом:

describe('home state', function() { 

    var $rootScope, $state, $injector, state = 'home'; 
    var getAllStub = sinon.stub(); 
    var items = { 
    getAll: getAllStub 
    }; 

    beforeEach(function() { 
    module('todo', function($provide) { 
     $provide.value('items', items); 
    }); 

    inject(function(_$rootScope_, _$state_, _$injector_) { 
     $rootScope = _$rootScope_; 
     $state = _$state_; 
     $injector = _$injector_; 
    }); 
    }); 

    it('should resolve items', function() { 
    getAllStub.returns('getAll'); 

    $state.go(state); 
    $rootScope.$digest(); 
    expect($state.current.name).toBe(state); 

    expect($injector.invoke($state.current.resolve.items)).toBe('findAll'); 
    }); 
}); 

Заранее спасибо за вашу помощь!

+0

Вашими Издевательская фабрика в порядке. Вы получаете сообщение об ошибке, потому что запрашивается шаблон '/home.html'. Разрешить реальный маршрутизатор в модульных тестах - плохая идея, потому что это ломает изоляцию и добавляет больше движущихся частей. Я лично считаю '$ StateProvider' и т. Д. Более точную стратегию тестирования. Вам просто нужно убедиться, что '$ stateProvider.state' вызывается с ожидаемым объектом конфигурации в качестве аргумента. Приложение может быть протестировано с помощью реального маршрутизатора в тестах интеграции/e2e, если это необходимо. – estus

+0

Мне нравится это предложение. Я попытался вытеснить '$ stateProvider' и' $ urlRouterProvider' так же, как и с 'items', но, к сожалению, я все еще вижу ту же ошибку, что и выше – davidicus

+0

. Я опубликовал ответ, который объясняет это. Обратите внимание, что вам не нужно проверять его с помощью '$ state.go' в этом случае (и в этой спецификации не будет никакой службы' $ state'). – estus

ответ

0

Разрешить реальный маршрутизатор в модульных тестах - плохая идея, поскольку он разбивает изоляцию и добавляет больше движущихся частей. Я лично считаю $stateProvider и т. Д. Более точную стратегию тестирования.

Информация о заказе важна в конфигурационных блоках, поставщикам услуг следует издеваться перед тем, как они будут введены в другие модули. Если исходные модули имеют config блоков, которые замещают издевались поставщики услуг, модули должны быть потушили:

beforeAll(function() { 
    angular.module('ui.router', []); 
    }); 

    beforeEach(function() { 
    var $stateProviderMock = { 
     state: sinon.stub().returnsThis() 
    }; 

    module(function($provide) { 
     $provide.constant('$stateProvider', $stateProviderMock); 
    }); 
    module('todo'); 
    }); 

Вам просто нужно, чтобы убедиться, что $stateProvider.state вызывается с ожидаемой конфигурацией объектов аргументов:

it('should define home state', function() { 
    expect($stateProviderMock.state.callCount).to.equal(1); 

    let [homeStateName, homeStateObj] = $stateProviderMock.state.getCall(0).args; 

    expect(homeStateName).to.equal('home'); 
    expect(homeState).to.be.an('object'); 

    expect(homeState.resolve).to.be.an('object'); 
    expect(homeState.resolve.items).to.be.an('array'); 

    let resolvedItems = $injector.invoke(homeState.resolve.items); 
    expect(items.getAll).to.have.been.calledOnce; 
    expect(resolvedItems).to.equal('getAll'); 

    ... 
    }); 
+0

Спасибо за ответ! Я все еще путаюсь, где точка входа для модульного теста. Раньше я использовал '$ rootScope. $ Digest()', чтобы инициировать разрешение, но здесь я не уверен, какую строку я должен писать для выполнения состояния. – davidicus

+0

Это фактическая спецификация, распознаватель проверяется на '$ injector.invoke', после чего вы можете вызвать дайджест, тогда преобразователь содержит код, который зависит от дайджестов. Вам вообще не нужно выполнять состояние, просто чтобы проверить правильность определения состояния с помощью '$ stateProvider'. Тот факт, что '$ state.go ('home')' изменяет состояние на 'home', уже был проверен UI Router! Если вам нужно также убедиться, что устройства работают отлично, без каких-либо сюрпризов, это задача интеграции/e2e Protractor. – estus

+0

Получил это. Последнее, когда я пытаюсь запустить тест, я получаю сообщение об ошибке в первой строке 'expect ($ stateProviderMock.state.callCount) .to.equal (1); 'потому что callCount по-прежнему равен нулю – davidicus