我有一个控制器测试,取决于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',$routeParams: {'pg': 'PG_FIRST'},}); MainCtrl = $controller('MainCtrl',$routeParams: {'pg': 'PG_SECOND'},});
解决方法
问题是,您不想做的事情可能是您拥有的最佳解决方案.当你想要模拟的东西有点复杂时,模拟是有意义的.与方法,许多状态等的复杂依赖关系对于像$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',$routeParams: {'PG': 'PG_SECOND'}}); }); it('Should ....',function() { expect($scope.something).toBe('PG_SECOND'); }); }); });
有了一个好的测试组织,我可以说我喜欢这个易于遵循的测试.