Mocking $ routeParams in a test to dynamically change its attributes

I have a control test that depends on the Angular $ routeParams service:

var $routeParams, MainCtrl, scope; beforeEach(inject(function ($controller, $rootScope, $injector, $templateCache) { scope = $rootScope.$new(); $routeParams = $injector.get('$routeParamsMock'); MainCtrl = $controller('MainCtrl', { $scope: scope, $routeParams: $routeParams, }); })); it('should load a pg from $routeParams', function(){ scope.userData = {}; $routeParams._setPg('PG_FIRST'); scope.$digest(); timeout.flush(); expect(scope.userData.pg).toBe(0); $routeParams._setPg('PG_SECOND'); scope.$digest(); timeout.flush(); expect(scope.userData.pg).toBe(1); }); 

$ routeParamsMock:

 !(function(window, angular){ 'use strict'; angular.module('vitaApp') .service('$routeParamsMock', function() { var _pg = null; return{ pg: _pg, _setPg: function(pg){ _pg = pg; } } }); })(window, window.angular); 

When debugging the test, I was surprised to learn that $ routeParamsMock.pg returned null each time, although I called _setPg with a different value.

This is because null is considered primitive (with the type of the object ...) and thus passed in the value ?, or, possibly, because Angular copies the object that is passed to the $ controller service.

The solution I'm looking for is preferably one that does not require the creation of different controllers in different test scenarios. eg:

  MainCtrl = $controller('MainCtrl', { $scope: scope, $routeParams: {'pg': 'PG_FIRST'}, }); MainCtrl = $controller('MainCtrl', { $scope: scope, $routeParams: {'pg': 'PG_SECOND'}, }); 
+4
source share
1 answer

The fact is that you do not want to make, probably, the best decision that you have. A mock makes sense when what you want to taunt is quite complex. Complex dependency on methods, many states, etc. For a simple object such as $routeParams , it makes the whole sense of the world by simply passing it a dummy object. Yes, this will require creating instances of different controllers for each test, but what?

Structure your tests in a way that makes sense, makes it readable and easy to follow.

I suggest you something like:

 describe('Controller: Foo', function() { var $controller, $scope; beforeEach(function() { module('app'); inject(function($rootScope, _$controller_) { $scope = $rootScope.$new();routeParams = {}; $controller = _$controller_; }); }); describe('With PG_FIRST', function() { beforeEach(function() { $controller('Foo', { $scope: $scope, $routeParams: {'PG': 'PG_FIRST'}}); }); it('Should ....', function() { expect($scope.something).toBe('PG_FIRST'); }); }); describe('With PG_SECOND', function() { beforeEach(function() { $controller('Foo', { $scope: $scope, $routeParams: {'PG': 'PG_SECOND'}}); }); it('Should ....', function() { expect($scope.something).toBe('PG_SECOND'); }); }); }); 

With a good test setup, I can say that I like this test, which is easy to follow.

http://plnkr.co/edit/5Q3ykv9ZB7PuGFMfWVY5?p=preview

+7
source

Source: https://habr.com/ru/post/1257795/


All Articles