2012-09-18 66 views
10

我想为嵌套的控制器编写单元测试,但无法弄清楚如何在我的测试中模拟相同的行为。嵌套控制器的单元测试

我有2个控制器:

function FirstController ($scope) { 
    $scope.childs = [{ 
     title : 'Hello, earth!' 
    }]; 
}; 

function SecondController ($scope) { 
    $scope.child.title = $scope.child.title + $scope.$index; 
}; 

在我的HTML:

<div data-ng-controller="FirstController"> 
    <div data-ng-repeat="child in childs" data-ng-controller="SecondController"> 
     {{ child.title }} 
    </div> 
</div> 

而这个工作正常(http://jsfiddle.net/tcayp/1/

的单元测试:

// FirstController 
it('Should have childs', function() { 
    scope = {}; 
    ctrl = new FirstController(scope); 
    expect(scope.childs.length).toBeGreaterThan(0); 
}); 
// SecondController 
it('Should have inherited a child', function() { 
    scope = {}; 
    ctrl = new SecondController(scope); 
    expect(scope.child.title).toEqual('Hello, earth!0'); 
}); 

在SecondController-test我无法弄清楚如何模拟ng-repeat的继承链。

回答

16

理想情况下,使用单元测试我们希望单独测试类(单元)。在一次测试中测试2个控制器可能太多:测试会变得更加复杂和更脆弱。

仔细看看所提供的示例,人们可能会注意到它并不是测试2控制器,而是确保数据在父范围内可用。因此,重点在一个控制器上只(SecondController)和继承的数据一个会写这样一个测试:

describe('Testing the SecondController controller', function() { 

    var $parentScope, $scope, ctrl; 
    it('should prepare title', inject(function($rootScope, $controller) { 

     //setup hierarchy of scopes with data    
     $rootScope.childs = [{ 
      title : 'Hello, earth!' 
     }]; 
     $scope = $rootScope.$new(); 
     $scope.$index = 1; 

     ctrl = $controller('SecondController', { 
      $scope: $scope 
     }); 

     expect($scope.childs[0].title).toEqual('Hello, earth!1');   
    })); 
}); 

以下是完整的的jsfiddle:http://jsfiddle.net/pkozlowski_opensource/h8xry/13/

我真的建议对检测2个控制器在一起,但只是为了回答这个问题的缘故,这是可能的:

describe('Testing the SecondController controller', function() { 

    it('should prepare title', inject(function($rootScope, $controller) { 

     $controller('FirstController', { 
      $scope: $rootScope 
     }); 

     var $scope = $rootScope.$new(); 
     $scope.$index = 1; 

     ctrl = $controller('SecondController', { 
      $scope: $scope 
     }); 

     expect($scope.childs[0].title).toEqual('Hello, earth!1');   
    })); 
}); 

而且的jsfiddle:http://jsfiddle.net/pkozlowski_opensource/4Qy6b/1/

+0

谢谢,我重写了它,以便它使用您的第一个示例。 – fredrik

2

AngularJS documentation建议通过实例化每个控制器并在它们之间建立与您的应用程序相同的范围层次结构来测试嵌套控制器。这是有道理的,因为(直到某一点)你想在真实的环境中测试你的控制器。

1

在您的测试实例父控制器以新的范畴:

childScope = mainScope.$new(); 
$controller('ChildController', {$scope: childScope}); 

例如,从AngularJS documentation

mainScope = $rootScope.$new(); 
$controller('ParentController', {$scope: mainScope}); 

,并在你的孩子控制器,使用先前已实例范围实例化一个新的作用域:

describe('state', function() { 

    var mainScope, childScope, grandChildScope; 

    beforeEach(module('myApp')); 

    beforeEach(inject(function($rootScope, $controller) { 
     mainScope = $rootScope.$new(); 
     $controller('MainController', {$scope: mainScope}); 
     childScope = mainScope.$new(); 
     $controller('ChildController', {$scope: childScope}); 
     grandChildScope = childScope.$new(); 
     $controller('GrandChildController', {$scope: grandChildScope}); 
    })); 

    it('should have over and selected', function() { 
     expect(mainScope.timeOfDay).toBe('morning'); 
     expect(mainScope.name).toBe('Nikki'); 
     expect(childScope.timeOfDay).toBe('morning'); 
     expect(childScope.name).toBe('Mattie'); 
     expect(grandChildScope.timeOfDay).toBe('evening'); 
     expect(grandChildScope.name).toBe('Gingerbread Baby'); 
    }); 
});