describe('#myFunction', function () {
    it('should be a function', function () {
        expect(angular.isFunction(myFunction)).toBeTruthy();
    });
});

From a TDD standpoint starting by defining a test that checks if we have a function can tell us if everything has been setup correctly. It also tells us straightaway that nothing has overwritten the expected function.

We also have some tests for checking if a function is defined. These seem pretty redundant.

describe('TestSuite', function () {
    // Mocks
    var serviceMock = {
        get: jasmine.createSpy()
    };

    ...

    serviceMock.get.andReturn(deferred.promise);

    ...

    it('should call service', function () {
        expect(serviceMock.get)
            .toHaveBeenCalledWith('param');
    });
});

Services get mocked using Jasmine's createSpy to allow us to see what they are being called with. The spies return a promise allowing us to resolve or reject the promise in the tests.

service.get('param')
    .then(function () {
        // Success    
    })
    .catch(function () {
        // Error
    });

Data in resolves only has to be the correct and structured data, like we get from the backend, if we are doing manipulations on it.

 

In cases where we just want to know if a variable has been set return as little mock data as possible to keep the tests light.

it('should return the correct data', function () {
    var success = jasmine.createSpy();

    service.transaction.get(12).then(success);

    deferred.resolve({
        data: 'getTransaction'
    });

    rootScope.$digest();

    expect(success)
        .toHaveBeenCalledWith('getTransaction');
});

More complex

When a function returns a promise the tests get a bit more complex and hard to follow.

function getTransaction(id){
    var deferred = $q.defer();
    var paymentId = {
        paymentId: id
    };

    fetchPaymentService
        .createRequest(paymentId)
        .send()
        .then(function(result) {
            deferred.resolve(result.data);
        }).catch(function (reason) {
            deferred.reject();
        });

    return deferred.promise;
}

More complex

Directive tests are harder than controller and service tests to understand. Especially the ones that contain an isolated scope.

function createDirective () {
    var html = '<swed-bar-chart data="aggregate"></swed-bar-chart>';

    var elem = angular.element(html);
    chartElement = compile(elem)(scope);
    scope.$digest();

    isolateScope = chartElement.isolateScope();

    return chartElement;
}
function activate() {
    expenseControl.on('change', onChange);
    expenseControl.accountList.load();
    expenseControl.aggregate.load();
}

function onChange() {
    vm.aggregate = expenseControl.aggregate.chartData();
    $scope.$safeApply();
}

More complex

Testing events from EventEmitter2 which is used in the models. In this example I don't know how to test the onChange function (unless I make it available on the view model)

Unit testing

By Rickard Laurin

Unit testing

  • 501