Angular.js Unit Test with Custom Service Example

(Updated 7/13/2014)

I've been working a lot with Angular.js lately, and there were a lot of unknowns for me when it came to unit testing my code. Below is an example that I hope will help other people who have questions about how to write unit tests for Angular.

I use Jasmine as the unit testing framework, and in the example below I'm testing controller named DocumentController which makes use of a service called AttachmentService. In the example below, we're testing the ability of the DocmentController to delete attachments, which it does with the help of AttachmentService.

I've commented it heavily in an attempt to be very clear as to what this code is doing. I hope this helps you. :)

//References to the JS files that are required by these tests and everything involved.
//The order matters!

/// <reference path="../jasmine/jasmine.js" />
/// <reference path="../jasmine/boot.js" />
/// <reference path="../angular.js" />
/// <reference path="../angular-mocks.js" />
/// <reference path="../underscore.js" />
/// <reference path="../ui-bootstrap-0.10.0.js" />
/// <reference path="../ui-bootstrap-tpls-0.10.0.js" />
/// <reference path="../App/app.js" />
/// <reference path="../App/Controllers/DocumentController.js" />
/// <reference path="../App/jquery.fileupload-angular.js" />

//Describe our test "Spec" (Specification)
describe("Ang: DocumentController Tests ->", function () {

    var _scope;
    var _controller;

    //This is equivalent to calling angular.mocks.module() -- NOT angular.module(). 
    //Every time you call angular.module() it recreates the module, so that would be bad here.
    //Instead, angular.mocks.module() loads up our module for testing.
    //IMPORTANT: We need to call this in a seperate beforeEach() than the one below, or else
    //you'll get an error about the injector already having been created and not being able        
    //to create a new module.
    beforeEach(module("myApp"));

    beforeEach(inject(function ($injector, $rootScope, $controller) {

        var attachmentServiceMock;

        //For more than one service, I would put service mocking into seperate method(s)
        attachmentServiceMock = {
            execute: function (url, method, successCallback, errorCallback) {
                successCallback();
            }
        };

        _scope = $rootScope.$new();     //Get a new scope for injection
        expect(_scope).not.toBeNull();  //Make sure the new scope isn't null
        _scope.model = [];              //Init our model

        //Instantiate the controller instance we'll be testing with, 
        //passing in the dependencies
        _controller =
            $controller('DocumentController',
                {
                    $scope: _scope,
                    AttachmentService: attachmentServiceMock,
                });

        //Make sure the controller isn't null
        expect(_controller).not.toBeNull();
    }));

    it("should delete attachment successfully", function () {

        //Our fake attachments. The actual values aren't really needed, but help to illustrate
        _scope.attachments = [
                { deleteUrl: "http://someurl/delete/blah.jpg/1", deleteType: "DELETE" },
                { deleteUrl: "http://someurl/delete/blah2.jpg/1", deleteType: "DELETE" },
                { deleteUrl: "http://someurl/delete/blah3.jpg/1", deleteType: "DELETE" }
        ];

        //Create a spy on window.confirm() so we can fake the "OK" button click
        spyOn(window, 'confirm').and.returnValue(true);

        //Call the method we're testing
        _scope.deletePreviouslyUploadedAttachment(1);

        //Confirm expected result
        expect(_scope.attachments.length).toEqual(2);
    });

    //..other tests...
});

Comments

John Dudley said…
The custom software development delhi at Acetetch take into account your long term business benefits without compromising on the quality aspect while at the same time maintaining the best practices of software development. We believe in building a long standing partnership with our valued clients by designing, developing, maintaining and improving software development services

Popular posts from this blog

A Generic Method Using HttpClient to Make a Synchronous Get Request

The Cause and Solution for the "System.Runtime.Serialization.InvalidDataContractException: Type 'System.Threading.Tasks.Task`1[YourTypeHere]' cannot be serialized." Exception

"$.ajax is not a function" Error When Using jQuery and Darren Johnstone's ASP.NET Upload/Download Module v2