【问题标题】:Mocking $routeParams in a test in order to change its attributes dynamically在测试中模拟 $routeParams 以动态更改其属性
【发布时间】:2014-11-01 10:27:17
【问题描述】:

我有一个依赖于 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 服务的对象?

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

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

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

【问题讨论】:

    标签: angularjs unit-testing jasmine karma-runner


    【解决方案1】:

    问题是,您不想做的事情可能是您拥有的最佳解决方案。当你想模拟的东西有点复杂时,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');
        });
      });
    });
    

    有了一个好的测试组织,我可以说我喜欢这个简单易懂的测试。

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

    【讨论】:

    • 我不想要这个的原因,是因为我在控制器中除了 $scope 和 $routeParams 之外还有许多其他依赖项
    • 我听说你的朋友,但我想不出办法。不是很干净。
    猜你喜欢
    • 2016-04-18
    • 2018-08-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 1970-01-01
    • 2021-06-26
    • 1970-01-01
    • 2013-06-17
    相关资源
    最近更新 更多