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.add is called correctly without changing its behavior, spying would be better.
  • Full mocking, why do we even need it?