How To Spy on Classes
// #jest#testing // 3 comments
Spying in Jest allows us to mock classes while keeping the original implementation intact. A spy
can help us verify if a certain method was invoked, without interfering with its functionality. However, the process of spying can vary, especially when dealing with class methods versus simple functions. There are three main scenarios we need to deal with: spying on static methods, spying on methods of a single instance, and spying on methods of all instances of a class.
Spying on Static Methods
Static methods are associated with the class itself, not with any specific instance of the class. This makes spying on them relatively straightforward. We simply reference the class and specify which static method we want to spy on.
class Person { static hello() { return 'Hello, I am a static method.'; } goodbye() { return 'Goodbye, I am an instance method.'; } } test('should call static method', () => { // Spy on the static method const spy = jest.spyOn(Person, 'hello'); // Invoke the static method Person.hello(); // Test if the static method has been called expect(spy).toHaveBeenCalled(); });
Spying on Methods of a Single Instance
In scenarios where we have access to a particular instance of the class, we can set a spy on any of this instance's methods. We simply reference the instance and the method we want to spy on.
class Person { static hello() { return 'Hello, I am a static method.'; } goodbye() { return 'Goodbye, I am an instance method.'; } } test('should call instance method of single object', () => { // Create an instance of the class const person = new Person(); // Spy on the instance method const spy = jest.spyOn(person, 'goodbye'); // Invoke the method on the instance person.goodbye(); // Test if the method on the instance has been called expect(spy).toHaveBeenCalled(); });
Spying on Methods of All Instances
In many real-world cases, we may not have access to the specific instance of the class we want to spy on. This instance might be hidden in a module we are testing and not directly exported or accessible from our test case. In such situations, we may choose to spy on all instances of a class. To do this, we reference the prototype of the class and the method we want to spy.
class Person { static hello() { return 'Hello, I am a static method.'; } goodbye() { return 'Goodbye, I am an instance method.'; } } // Create an instance and call the instance method function goodbye() { const person = new Person(); return person.goodbye(); } test('should call instance method of all objects', () => { // Spy on the instance method for all instances const spy = jest.spyOn(Person.prototype, 'goodbye'); // Call function without access to underlying instance goodbye(); goodbye(); // Test if the method has been called on any instance expect(spy).toHaveBeenCalledTimes(2); });