Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing with Jasmine: code in beforeEach() not seen by test's spyOn()

New to unit testing in general and Jasmine in particular.

I've set a variable in a beforeEach() callback, but it doesn't seem to work on the second test. It's supposed to fire initialization stuff in advance of every test within its context, right? I'm sure my spyOn() call is to blame, but I don't know how to fix it.

Comments explain the passes and fails:

describe("Test suite for my library", function () {
  var html,
      body,
      play,
...

  // custom matcher...
  beforeEach(function () {
    this.addMatchers({
      toBeInstanceOf : function (constructr) {
        return this.actual instanceof constructr;
      });
    });
  });

  describe("Within the Button object", function () {

    beforeEach(function () {
      play = new Button("play", false);
    });

    describe("play", function () {

      // This test passes, as expected...
      it("should be an instance of the Button object", function () {
        expect(play).toBeInstanceOf(Button);
      });

    });

    describe("play.name", function () {

      // This test failed with the message
      // "Expected spy Button to have been called
      //  with [ 'play', false ] but it was never called."
      it("should be the first argument passed to the Button constructor", function () {
        spyOn(window, "Button");
        play = new Button("play", false); // ...until I added this line. Now it passes.
        expect(window.Button).toHaveBeenCalledWith("play", false);
      });

      // This test passes, even if the one above fails.
      it("should be 'play'", function () {
        expect(play.name).toBe("play");
      });

    });

  });
});

The documentation explains the usage, but not the context, of spyOn(), so I can't tell if I've created a bug or if I'm unknowingly taking advantage of a feature.

I can post the constructor if anyone thinks it makes any difference in the diagnosis, but I can assure you it's dead simple.

I'm sure it's a straightforward fix using some basic unit testing concept I'm having to learn the hard way. Thanks in advance.

P.S. I realize what I'm testing for in that failing spec isn't what I've described. I'm working my way through the API guide, looking for a way to get to the arguments array within a function call, so I can do a specific test on arguments[0]. Hints are appreciated, but not necessary. I'll figure it out.

like image 379
parisminton Avatar asked Dec 16 '22 05:12

parisminton


1 Answers

Short answer: No, Before each and spies are not incompatible

You must Spy before you call if you want the spy to know about the call. You can use spyOn(object, 'function').andCallThrough() if you do not wish to interfere with its default behavior.

Long answer: The way faking/mocking/stubbing/spying frameworks often work is by replacing the method you are calling with a method that the mocking framework can control. Any calls to that function before it is replaced with the spy cannot be observed. This is a good thing, though mildly inconvenient,

like image 144
Zee Spencer Avatar answered Dec 29 '22 01:12

Zee Spencer