Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I mock an Angular service using jasmine?

This may be a duplicate but I have looked at a lot of other questions here and they usually miss what I am looking for in some way. They mostly talk about a service they created themselves. That I can do and have done. I am trying to override what angular is injecting with my mock. I thought it would be the same but for some reason when I step through the code it is always the angular $cookieStore and not my mock.

I have very limited experience with jasmine and angularjs. I come from a C# background. I usually write unit tests moq (mocking framework for C#). I am use to seeing something like this

[TestClass]
public PageControllerTests
{
    private Mock<ICookieStore> mockCookieStore;
    private PageController controller;

    [TestInitialize]
    public void SetUp()
    {
        mockCookieStore = new Mock<ICookieStore>();
        controller = new PageController(mockCookieStore.Object);
    }

    [TestMethod]
    public void GetsCarsFromCookieStore()
    {
        // Arrange
        mockCookieStore.Setup(cs => cs.Get("cars"))
                    .Return(0);

        // Act
        controller.SomeMethod();

        // Assert
        mockCookieStore.VerifyAll();
    }
}

I want mock the $cookieStore service which I use in one of my controllers.

app.controller('PageController', ['$scope', '$cookieStore', function($scope, $cookieStore) {

    $scope.cars = $cookieStore.get('cars');

    if($scope.cars == 0) {
            // Do other logic here
            .
    }

    $scope.foo = function() {
        .
        .
    }
}]);

I want to make sure that the $cookieStore.get method is invoked with a 'garage' argument. I also want to be able to control what it gives back. I want it to give back 0 and then my controller must do some other logic.

Here is my test.

describe('Controller: PageController', function () {

    var controller,
        scope,
        cookieStoreSpy;

    beforeEach(function () {
        cookieStoreSpy = jasmine.createSpyObj('CookieStore', ['get']);
        cookieStoreSpy.get.andReturn(function(key) {
            switch (key) {
                case 'cars':
                    return 0;
                case 'bikes':
                    return 1;
                case 'garage':
                    return { cars: 0, bikes: 1 };
            }
        });

        module(function($provide) {
            $provide.value('$cookieStore', cookieStoreSpy);
        });
        module('App');

    });

    beforeEach(inject(function(_$httpBackend_, $rootScope, $controller) {
        scope = $rootScope.$new();
        controller = $controller;
    }));

    it('Gets car from cookie', function () {
        controller('PageController', { $scope: scope });
        expect(cookieStoreSpy.get).toHaveBeenCalledWith('cars');
    });
});
like image 620
uriDium Avatar asked Oct 02 '13 08:10

uriDium


1 Answers

This is a solution for the discussion we had in my previous answer.

In my controller I'm using $location.path and $location.search. So to overwrite the $location with my mock I did:

locationMock = jasmine.createSpyObj('location', ['path', 'search']);
locationMock.location = "";

locationMock.path.andCallFake(function(path) {
  console.log("### Using location set");
  if (typeof path != "undefined") {
    console.log("### Setting location: " + path);
    this.location = path;
  }

  return this.location;
});

locationMock.search.andCallFake(function(query) {
  console.log("### Using location search mock");
  if (typeof query != "undefined") {
    console.log("### Setting search location: " + JSON.stringify(query));
    this.location = JSON.stringify(query);
  }

  return this.location;
});

module(function($provide) {
  $provide.value('$location', locationMock);
});

I didn't have to inject anything in the $controller. It just worked. Look at the logs:

LOG: '### Using location set'

LOG: '### Setting location: /test'

LOG: '### Using location search mock'

LOG: '### Setting search location: {"limit":"50","q":"ani","tags":[1,2],"category_id":5}'

like image 180
gnom1gnom Avatar answered Sep 18 '22 21:09

gnom1gnom