1

So I am testing a controller, which is referencing a property specified as ngModel in DOM. But while I am testing my controller, I don't have the template. So whenever $scope.foo.property is being accessed in the controller, it throws an error.

M T
  • 4,099
  • 4
  • 21
  • 27
  • Can you provide a mock template? – Robert Harvey Jul 31 '13 at 17:34
  • Mock template, well I am testing the controller, why should I need the mock template for ? The tutorials state, "In angular the controllers are strictly separated from the DOM " – M T Jul 31 '13 at 17:45
  • Indeed. Which raises the question, why do you need the template? – Robert Harvey Jul 31 '13 at 17:46
  • So in you are suggesting if a property foo.property is being accessed in controller, then I am breaking the convention and making the code untestable ? – M T Jul 31 '13 at 17:56

2 Answers2

1

In your test, you can define your property before instantiate your controller :

it('should mock ng-model', inject(function($rootScope, $controller) {

    $rootScope.foo = {
        property: 'mock value'
    };

    $controller('myController', {$scope: $rootScope});
})));
Bastien Caudan
  • 4,482
  • 1
  • 17
  • 29
  • THe foo.property is of type NgModelController, not sure how to create instance or mock that. – M T Aug 01 '13 at 04:02
  • You want to test your controller and its interactions with this property, not the ngModelController ? – Bastien Caudan Aug 01 '13 at 08:11
  • This is something I did, say for instance I have a ngModelConroller instance being referred in the controller, so I would mock the ngModelController instance, with mocked methods say $setValidity and injected it into the scope and passed it around the controller. So this way I can test if the method $setValidity was called, if my functional spec conclues this. – M T Aug 04 '13 at 17:19
  • I think that if you want to use ngModelController you should be in a directive linking function and not in a module controller. Maybe this can help : http://stackoverflow.com/questions/14115701/angularjs-create-a-directive-that-uses-ng-model – Bastien Caudan Aug 05 '13 at 17:47
0

Controllers and views (templates) are two separate things in Angular applications. What glues them together is the scope (or model). So, to test a controller all you need is a fake scope to pass to the controller function.

Here's a very simple example using a global controller (just to keep things easier to understand - don't use global controllers in production code) and a pseudo test function:

function MyCtrl($scope) {
    $scope.bar = $scope.foo.property + 1;
}

function test() {
    var scope = { foo: { property: 1 }};
    MyCtrl(scope);
    expect(scope.bar).toBe(2);  
}

It gets a little bit more complicated than that when the controller is defined within an module, but that's another story.

Michael Benford
  • 14,044
  • 3
  • 60
  • 60