2

I am starting out in JS unit testing and having a hard time getting my head around how to create meaningful tests with Jasmine spies.

it('should take an array of shopping items', function() {
  spyOn(checkObj, 'getTotal');
  checkObj.getTotal([1, 2, 3]);
  expect(checkObj.getTotal).toHaveBeenCalledWith(jasmine.any(Array));
});

Using the above excerpt of test I created as an example I cant see how this is a useful test as my call to getTotal is hard coded inside the spec. But at the same time I would like to ensure the param passed is an array and not some other type...its the hard coding that I am sure is wrong somehow.

Could someone offer a bit of guidance on how I should think/approach this type of testing scenario

user1806692
  • 143
  • 1
  • 10
  • I think you are looking at the wrong problem here. The question is _what_ are you trying to test? The code you have now is rather useless - you call it with an array and on the following line check if it's been called with an array. That is literally testing your test. It's not a useful thing to verify, in other words. What do you want to check here is the better question? If you want to check that `getTotal` only accepts arrays, then you probably need to call it with other stuff and expect some sort of error. – VLAZ Oct 05 '16 at 22:00
  • Thanks for the comment vlaz, what you said makes sense, it feels like I am doing the wrong thing using toHaveBeenCalledWith to test the argument and it would be better to simply test the output of the method. I will also give your ideas a go...all I wanted to check was that an array is being passed as the argument but not sure if I am trying to over test stuff – user1806692 Oct 06 '16 at 08:15

1 Answers1

1

Well, spies are useful for a bit different scenario. Much depends on how you yourself define the scope of your unit test as well. If you do the minimal possible unit (i.e. method) then lets imagine the following:

var x = function() { }
x.prototype.f1 = function() { 
        //do something 
        },
x.prototype.f2 = function(){
          // do something else
          this.f1();
        }

Now, in your unit test for f2 you are not interested in how f1 works inside. so, you make a spy on it:

var a = new x();
a.f1 = jasmine.createSpy("spy-on-f1");
expect(a.f1).not.toHaveBeenCalled();
a.f2();
expect(a.f1).toHaveBeenCalled();

For example, for angularjs applications, I often mock whole services with spies, just to isolate the algorithm in testing.

As a bonus, you can actually replace the real call with some fake function like this:

a.f1 = jasmine.createSpy("fake-spy").and.callFake(function(){
    // do something predictible or return global variable that can be set externaly
});
Vladimir M
  • 4,403
  • 1
  • 19
  • 24