在测试中模拟$ routeParams以动态更改其属性

Ole*_*sov 4 unit-testing jasmine angularjs karma-runner

我有一个控制器测试,取决于Angular $ routeParams服务:

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);
});
Run Code Online (Sandbox Code Playgroud)

$ 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);
Run Code Online (Sandbox Code Playgroud)

在调试测试时,我很惊讶地发现$ routeParamsMock.pg每次都返回null,即使我用不同的值调用_setPg.

是因为null被认为是一个原语(具有一种对象......),因此通过值传递?,或者可能是因为Angular正在复制传递给$ controller服务的对象?

我正在寻找的解决方案最好是不需要为每个不同的测试场景设置不同控制器的解决方案.例如:

    MainCtrl = $controller('MainCtrl', {
        $scope: scope,
        $routeParams: {'pg': 'PG_FIRST'},
    });

    MainCtrl = $controller('MainCtrl', {
        $scope: scope,
        $routeParams: {'pg': 'PG_SECOND'},
    });
Run Code Online (Sandbox Code Playgroud)

Jes*_*uez 7

问题是,您不想做的事情可能是您拥有的最佳解决方案.一个mock是有道理的,当你想嘲笑什么是有点复杂.与方法,许多状态等的复杂依赖关系.对于像$routeParams它这样的简单对象,只需将虚拟对象传递给它就可以了解世界.是的,每次测试需要实例化不同的控制器,但那又​​如何呢?

以有意义的方式构建测试,使其易读且易于理解.

我建议你这样的事情:

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');
    });
  });
});
Run Code Online (Sandbox Code Playgroud)

有了一个好的测试组织,我可以说我喜欢这个易于遵循的测试.

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