Christian Droulers

Agile and flexible programmer

Testing AngularJS controllers

Posted on 2015-04-26

So I just blogged about writing controllers in TypeScript. Here’s how to write tests for them now.

We recently refactored all our controllers to become classes and also (quite importantly) not use $scope.$watch anymore. We went this way after experiencing problems with $watch itself and testability. This blog article outlines good reasons not to do it.

Our general guideline is to now use JavaScript properties when we want to have a value changing affect another in the same model or a child model. We also use events when crossing model or controller borders.

With that in mind, anything that can be made to happen in a model is a straight forward test. Then, most things that can happen in a controller become easy to test as well! There should be a very limited set of actions that a controller can do. It can $emit or $broadcast events, it can call AJAX (via a service ideally) and it can respond to events.

Here’s a simple sample test class for a controller.

describe("app.controllers.YourController",() => {
    var scope: ng.IScope;
    var controller: app.controllers.YourController;
    var serviceMock:;
    var rootScope: ng.IRootScopeService;
    var q: ng.IQService;


    beforeEach(() => {
                $rootScope: ng.IRootScopeService, 
                $q: ng.IQService, 
                $injector: ng.IInjector) => {
            scope = <any>$rootScope.$new();
            rootScope = $rootScope;
            q = $q;

            serviceMock = jasmine.createSpyObj("", ["GetAll"]);

            controller = new app.controllers.YourController(

    it("should load all things",() => {

    describe("MyFunction",() => {
        it("should return true by default",() => {

        it("should return false when other thing is changed is false",() => {
            controller.OtherThing = false;

This is a very cut down example, but it demonstrates a few things. First, mocking a service is quite easy with Jasmine. Then, using $injector to get other dependencies you don’t need for testing if you’re too lazy to mock them (I know I was!).

Looking back, passing null into dependencies that aren’t used in the tests would be much easier… I’ll see about that later!

comments powered by Disqus