zmii
zmii

Reputation: 4277

testing angular service internal method calls

I have the following simple service

app.factory('Shoes', function() {
    function a() {return 12;}
    function b() {return a();}

    return {
      a: a,
      b: b
    }
  })

I want to test if the method a is being called when I call method b. My test looks like this:

describe('Testing a Shoes service', function() {
  var service;

  beforeEach(module('plunker'));

  beforeEach(inject(function(Shoes) {
    service = Shoes;
  }))

  it('.b should call .a', function() {
    spyOn(service, 'a');
    service.b();
    expect(service.a).toHaveBeenCalled();
  })

});

But the tests fail. Relevant plunker is here.

Question is how can I test this kind of interactions?

Upvotes: 0

Views: 1036

Answers (3)

Mickael
Mickael

Reputation: 5736

What happens here is that you set on a spy on service.a method, but the internal a (which is called internally by b) is still the same internal method (i.e not the spy), that's why your test fail.

If you really want to do that, the only way is to not call the internal a but the method of your service:

app.factory('Shoes', function() {
    return {
        a: function a() {
            return 12;
        },

        b: function b() {
            return this.a();
        }
    };
});

Here is an update of your plunkr: https://plnkr.co/edit/6FZptdcX9qwyOE6kbgAX

EDIT:

Just some explanation: the service.a method is just a pointer to the internal a method. When you say spyOn(service, 'a'), you are just overwriting the service.a pointer to point to a completely different method (i.e a spy created by jasmine). The internal a method is private and will be never updated, so if you call a() in your internal b method, you just call the original method a not the spy pointed by service.a.

Upvotes: 3

Ivan Iankovskyi
Ivan Iankovskyi

Reputation: 36

app.factory('Shoes', function() {

var self = {
  a: function() {return 12;},
  b: function() {return this.a();}
}

return {
  a: self.a,
  b: self.b
}
})

I believe that's because b is not calling the function you are spying on. With factory above test passes.

Upvotes: 0

Evgeny Sorokin
Evgeny Sorokin

Reputation: 730

I managed to fix this issue with the following code

app.factory('Shoes', function() {
    var module = {
      a:function(){
        return 12;
      },
      b: function(){
        return this.a();
      }
    }
    return module;
});

It seems like your tested module can't just call a "function". It should call the method of the object returned;

Updated Plunker: https://plnkr.co/edit/DeDmdQq3rguO6uGHElW6?p=preview

Upvotes: 0

Related Questions