Spy
A spy allows you to watch a real function and track its calls without changing its implementation.
import * as math from './math';
test('spy example', () => {
 const spy = jest.spyOn(math, 'add');
Â
 math.add(2, 3);
Â
 expect(spy).toHaveBeenCalledWith(2, 3);   Â
 expect(spy).toHaveBeenCalledTimes(1);
Â
 spy.mockRestore();
}); Mock
Mocking involves creating a fake object that simulates the behavior of a real object.
import * as math from './math';
test('mock example', () => {
 jest.spyOn(math, 'add').mockImplementation((a, b) => 100);
Â
 const result = math.add(2, 3);
Â
 expect(result).toBe(100);
 expect(math.add).toHaveBeenCalledWith(2, 3);
}); Stub
Stubs typically just replace a method with a fixed return value.
import  *  as math  from  './math';
test('stubbing math.add', () => {
 math.add = jest.fn(() => 42);
 const result = math.add(5, 3);
 expect(result).toBe(42);
 expect(math.add).toHaveBeenCalledWith(5, 3);
 expect(math.add).toHaveBeenCalledTimes(1);
}); When to use what?
Â
-  If you’re unit testing a function that uses
math.add, stubbing might be the best choice for its simplicity. -  If you’re doing integration testing and want to ensure
math.addis called correctly without changing its behavior, spying would be better. - Full mocking, why do we even need it?