mkosler
mkosler

Reputation: 322

Stubbing a scope method invoked in angular controller construction with sinon

I have a controller which upon construction calls a method attached to the $scope:

angular.module('example', []).controller('exampleCtrl', function($scope) {
    $scope.method = function () { ... };

    $scope.method();
});

I want to test that during the construction of the controller, this method gets called. I am using jasmine as my test framework and sinon.js for my mocking framework.

describe('tests', function() {
    var $scope, $controller;

    beforeEach(inject(function($rootScope, _$controller_) {
        $scope = $rootScope.$new();
        $controller = _$controller_;
    });

    describe('During construction', function() {
        it('should call "method"', function() {
            $controller('exampleCtrl', { $scope: $scope });

            var methodStub = sinon.stub($scope, 'method');

            expect(methodStub.called).toBe(true);
        });
    });
});

This fails because once $controller() is invoked, it immediately calls $scope.method() before I am able to stub it out. However, if I attempt to stub the method prior to construction,

it('should call "method"', function() {
    var methodStub = sinon.stub($scope, 'method');

    $controller('exampleCtrl', { $scope: $scope });

    expect(methodStub.called).toBe(true);
});

sinon throws an error: TypeError: Cannot read property 'restore' of undefined, because $scope.method is not defined because I haven't called the constructor!

I have also attempted to stub the method out directly on the $scope, i.e., $scope.method = sinon.stub(), but that gets overwritten during controller construction.

So, is it possible to stub a method invoked during construction?

Upvotes: 3

Views: 868

Answers (1)

milanlempera
milanlempera

Reputation: 2263

It will not work because controller always overwrites you stub.

It's more a question of clean code.

Firstly, the controller should not contain any complex logic. Usually it tests so that you mock dependencies and check if they are called properly.

Secondly, preferred controller notation is a "controller as". Controller is therefore a classic JS class. If you define method in the prototype, you can mock/stub it.

But in general the requirement is a bit unusual and may indicate that the controller makes it too much.

Upvotes: 1

Related Questions