angularunit-testingjasminetestbed

Mock helper classes in jasmine unit test


I want to unit test an angular component that uses a helper class. The helper class and its functions should not be part of this test and be mocked instead. The component may look like this:

import { MyHelperClass } from "./my-helper-class";

export class MyComponent {
    public doStuff() {
        const helper = new MyHelperClass();
        if (helper.check()) {
            // code I want to test
        }
    }
}

I want to keep out the functionality of helper.check() from the unit test and just assume it returns true (or false in a second test). So I want my test to look something like this:

it("#doStuff should do something, assuming helper.check() is true, () => {
    // make constructor of MyHelperClass return a Mock
    // (or somehow spy on helper.check() and return true?) 

    expect(component.doStuff()).toBe(someValue);
});

Solution

  • You can set up a spy that mocks the function call and returns whatever value you want for check(). It also lets you check if that function (e.g. the spy was actually invoked and how many times, etc.).

    The tricky part is, if you don't have an instance of the class, you need to set up your spy on the prototype of your class.

    Have a look at this code (dummyVariable is just a variable to test if the code after check() has been executed or not):

    it('doStuff should do something, assuming helper.check() is true', () => {
      // test the before value
      expect(component.dummyVariable).toBe(false);
    
      // set up the spy and make it return true
      const spy = spyOn(MyHelperClass.prototype, 'check').and.returnValue(true);
    
      // call our function
      component.doStuff();
    
      // check the after value
      expect(component.dummyVariable).toBe(true);
    
      // check if our spy/mocked function was actually called
      expect(spy).toHaveBeenCalledTimes(1);
    });
    
    // same thing as above but this time our spy returns false
    it('doStuff should do something, assuming helper.check() is false', () => {
      expect(component.dummyVariable).toBe(false);
    
      const spy = spyOn(MyHelperClass.prototype, 'check').and.returnValue(false);
      component.doStuff();
    
      expect(component.dummyVariable).toBe(false);
      expect(spy).toHaveBeenCalledTimes(1);
    });
    

    You can find a working example here.