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

Angularjs 在测试中模拟$routeParams以动态更改其属性,angularjs,unit-testing,jasmine,karma-runner,Angularjs,Unit Testing,Jasmine,Karma Runner,我有一个控制器测试,它取决于Angular$routeParams服务: var $routeParams, MainCtrl, scope; beforeEach(inject(function ($controller, $rootScope, $injector, $templateCache) { scope = $rootScope.$new(); $routeParams = $injector.get('$routeParamsMock'); MainCtr

我有一个控制器测试,它取决于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);
});
$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);
调试测试时,我惊讶地发现$routeParamsMock.pg每次都返回null,尽管我使用不同的值调用了_setPg

这是因为null被认为是一个原语(具有对象类型…),因此通过值传递,还是因为Angular正在复制传递给$controller服务的对象

我正在寻找的解决方案最好是不需要根据不同的测试场景实例化不同的控制器。 例如:


问题是,你不想做的,可能是你最好的解决方案。当您想要模拟的内容比较复杂时,
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');
    });
  });
});
有了一个好的测试机构,我可以说我喜欢这个容易遵循的测试


我不想这样做的原因是,除了$scope和$routeParam之外,我在控制器中还有许多其他依赖项。我听说你是mate,但我想不出一个方法来实现这一点。不是干净的。
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');
    });
  });
});