3

I am faced with what is I believe a very straightforward scenario, but I cannot find a clear answer: I have a controller which does a number of things when created, including somewhat complicated stuff, and so I have created an initialization function to do it.

Here's what the controller code looks like:

function MyCtrl() {
    function init() {
            // do stuff
    }
    var vm = this;
    vm.init = init;
    vm.init();
}

Obviously, I want to unit test init(), but I cannot find a way to do so: when I instanciate the controller in my tests, init() is run once, which makes it hard to correctly test its side-effects when I run it a second time.

I'm using karma-jasmine for the tests, and usually do something like this:

describe('Controller: MyCtrl', function () {
    var myCtrl;
    beforeEach(angular.mock.module('myApp'));
    beforeEach(inject(function ($controller, $rootScope) {
        $scope = $rootScope.$new();
        createController = function () {
            return $controller('MyCtrl', {$scope: $scope});
        };
    }));
    it('bleh', function() {
        myCtrl = createController();
        // init has already been run at that point
    });
)};

Again, I'm sure it's really straightforward and I'm simply missing the point, but I'm still fairly new to Angular. Thanks a lot for your help!

Augustin
  • 61
  • 6
  • Well, createController() calls init(). So, just test that calling createController() does what it's supposed to do, i.e. has "done stuff" correctly. – JB Nizet Mar 02 '16 at 07:34
  • Thanks for answering! My problem is that it's not only init() that's being called. Also, I simplified my example, but there may be several different "init" functions, precisely so that their logic can be tested independently. (btw and slightly off-topic: I've loved your tutorial on promises, it was really great and helped a lot, so thank you!) – Augustin Mar 02 '16 at 07:46
  • It's a chicken and egg problem: init is called by the constructor, and you need to call the constructor in order to call your init function(s). I still maintain that the fact that you have one or several "private" functions called by the constructor is an implementation detail. What you really want to test is that the constructor does its job. You could simplify that by delegating to service functions (that could be unit tested, and mocked when testing the controller). – JB Nizet Mar 02 '16 at 09:32
  • OK, if there is no other solution, then I guess I'll have to do it that way. What do you think of the controller running a function when instanciated? Would you say there are better ways to achieve that, which allow better testing? – Augustin Mar 02 '16 at 16:33

1 Answers1

2

Putting JB Nizet's answer here instead of in a comment.

Many thanks for answering!

It's a chicken and egg problem: init is called by the constructor, and you need to call the constructor in order to call your init function(s). I still maintain that the fact that you have one or several "private" functions called by the constructor is an implementation detail. What you really want to test is that the constructor does its job. You could simplify that by delegating to service functions (that could be unit tested, and mocked when testing the controller).

Augustin
  • 61
  • 6