Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing controller with injected service inside angularJS with jasmine

I am trying to understand how to test my code with jasmine and angularJS. I wrote a test project with a controller and an injected service. Now i want to test the controller and tried to mock the injected service. But i didn’t found a way to test the function “Arrived” from my controller. Here’s my jsfiddle: http://jsfiddle.net/2fwxS/

controller.js:

angular.module('myApp.controllers', [])
    .controller('MyCtrl', ['$scope', 'MyService', function ($scope, MyService) {
    $scope.User = {};
    $scope.HasUserArrived = false;
    $scope.Arrived = function(firstname, lastname) {
    $scope.HasUserArrived = MyService.Arrive(firstname, lastname);
    return $scope.HasUserArrived;
    }
}]);

services.js:

var myApp = angular.module('myApp.services', []).
  value('version', '0.1');

myApp.factory('MyService', [function () {
    return {
        HasArrived: false,
        Arrive: function (firstname, lastname) {
            this.HasArrived = false;

            if (firstname && lastname) {
                this.HasArrived = true;
            }

            console.log("User has arrived: " + this.HasArrived);
            return this.HasArrived;
        }
    }
}]);

I found some similar explanations where $provide could be the correct solution (How can I write jasmine test for angular controller and service like this?) or createSpy (How do you mock Angular service that is a function?) but I wasn’t able to understand when I need $provider.factory or $provider.value or when should I use createSpy?

I would appreciate if someone could help me to understand the differences and gets the deactivated code in my jsFiddle (http://jsfiddle.net/2fwxS/) example up and running...

like image 479
burgerS Avatar asked Aug 11 '13 19:08

burgerS


1 Answers

You should use $provide.value in order to replace the original service instance with a mocked one:

beforeEach(module(function($provide) {
    var service = { 
        Arrive: function (firstname, lastname) {
            if (firstname && lastname) {
                return true;
            }
        }
    };
    $provide.value('MyService', service);
}));

I really don't know why $provide.value works but $provide.factory doesn't. I'll try to take a look at the Angular code later so I can figure it out. I'll update this answer if I find out something.

About spies, you should use them if you want to test that your mocks are being used the way they are supposed to. That includes checking parameters and invocations. Here's your code changed to use a spy:

it('checks that Arrived is correctly used', function() {
    // Arrange
    spyOn(service, 'Arrive');

    // Act
    scope.Arrived('Franz', 'Kafka');

    // Assert
    expect(service.Arrive).toHaveBeenCalledWith('Franz', 'Kafka');
});

Here's your fixed jsFiddle.

like image 50
Michael Benford Avatar answered Nov 15 '22 19:11

Michael Benford