Ever spent more time fixing your tests than your actual code? Chances are, your mocks are mocking you.
🤔 What Is Mocking, Anyway?
Mocking is basically replacing real parts of your code with fake versions during testing.
Think of it like a movie set. You don’t build a real city for every scene — you build a set that looks like a city. That’s mocking.You do this because real stuff — like APIs, databases, or email services — are slow, flaky, or just out of your control.
🎯 Why Use Mocks?
Because you want to isolate the thing you’re testing.
Before you write a single line of test code, ask yourself:
- What am I actually testing?
- What does this unit depend on?
- Which parts are external or already tested?
Mocks help you focus on your own code — not everyone else’s.
âś… What to Mock
💡 Rule of Thumb : Mock anything that’s not part of the code you’re actually testing.That usually means:
- External API calls, database calls, filesystems, email or logging systems
- Third-party libraries
- Business logic that’s tested somewhere else
❌ What Not to Mock
This part is actually more important — and trickier — than knowing what to mock.
Here’s what you shouldn’t mock:
- Don’t mock the code you’re actually trying to test. That defeats the purpose of writing the test in the first place.
- Also avoid mocking code that’s simple, stable, and has no side effects — mocking it just adds noise and brittleness.
Let’s look at an example 👇
đź§Ş UserService.ts
// userService.ts
import axios
from 'axios' ;
import {
format }
from 'date-fns' ;
import {
writeLog }
from './logger' ;
import {
calculateUserScore }
from './utils' ;
import {
parseInt }
from 'lodash' ;
export
class UserService {
async fetchAndProcessUser ( userId : string ): Promise < number > {
const response = await axios. get ( `https://api.example.com/users/ ${userId} ` );
const user = response. data ;
const score = parseInt ( calculateUserScore (user));
writeLog ( `User ${userId}
processed at ${format( new Date (), 'yyyy-MM-dd HH:mm' )} ` );
return score; } }
import axios
from 'axios' ;
import {
format }
from 'date-fns' ;
import {
writeLog }
from './logger' ;
import {
calculateUserScore }
from './utils' ;
import {
parseInt }
from 'lodash' ;
export
class UserService {
async fetchAndProcessUser ( userId : string ): Promise < number > {
const response = await axios. get ( `https://api.example.com/users/ ${userId} ` );
const user = response. data ;
const score = parseInt ( calculateUserScore (user));
writeLog ( `User ${userId}
processed at ${format( new Date (), 'yyyy-MM-dd HH:mm' )} ` );
return score; } }
âť“ What am I actually testing here?
- The method fetches user data from an API,
- Then processes it using your business logic,
- And returns the correct score.
🧼 What’s External or Already Tested?
✅ Don’t mock calculateUserScore()
It’s your own logic, sure — but if it already has its own tests, trust those. Here, you're just checking that this service uses it correctly, not recalculating its internals. Think: “I know my calculator works — I’m just testing if I pressed the button.”
✅ Don’t mock _.parseInt() (Lodash)
It's a tiny, stable, well-tested utility. Mocking it adds complexity for no gain. Trust it unless it’s causing problems (spoiler: it won’t).
🔌 Mock axios.get()
It hits the network — slow, flaky, and external. Perfect candidate for mocking so your test stays fast and reliable.
🔌 Mock writeLog()
Logging is a side effect. You don’t care about its output in a unit test — you just want to know it was called (maybe with the right message). Mock it.
đź§® How Many Mocks Are Too Many?
Great question.
If you’re mocking more than 2–3 things in a single test, stop and ask: “Am I testing too much at once?”Most solid unit tests only need 1–3 mocks. If you’re mocking 5+ things, you might be testing too much at once — consider splitting or refactoring.
If you’re mocking everything in sight, you may need to split up your code or rethink what “unit” you’re testing.
Corrected Example,
// userService.test.ts
import axios
from 'axios' ;
import {
writeLog }
from './logger' ;
import {
UserService }
from './userService' ;
jest. mock ( 'axios' );
jest. mock ( './logger' );
test ( 'fetchAndProcessUser returns correct score' , async () => {
(axios. get jest. Mock ). mockResolvedValue ({
data : {
: 'u1' , name : 'Alice' , activity : [, , ] }, });
const logSpy = jest. spyOn (writeLog, 'default' ). mockImplementation ( () => {});
const service = new UserService ();
const score = await service. fetchAndProcessUser ( 'u1' );
expect (score). toBe (); // assuming score is sum of activity expect (logSpy). toHaveBeenCalled (); });
import axios
from 'axios' ;
import {
writeLog }
from './logger' ;
import {
UserService }
from './userService' ;
jest. mock ( 'axios' );
jest. mock ( './logger' );
test ( 'fetchAndProcessUser returns correct score' , async () => {
(axios. get jest. Mock ). mockResolvedValue ({
data : {
: 'u1' , name : 'Alice' , activity : [, , ] }, });
const logSpy = jest. spyOn (writeLog, 'default' ). mockImplementation ( () => {});
const service = new UserService ();
const score = await service. fetchAndProcessUser ( 'u1' );
expect (score). toBe (); // assuming score is sum of activity expect (logSpy). toHaveBeenCalled (); });
✌️ Wrapping Up
Mocking isn’t evil. It’s one of your best tools — when used wisely. Mocking helps you keep tests fast, reliable, and focused.
âś… Mock things that are external, flaky, or irrelevant to the test.
❌ Don’t mock what you actually care about verifying.
Keep your tests focused, fast, and meaningful.
And next time you’re not sure whether to mock something, just ask:
“Am I testing my logic, or just checking that mocks return what I told them to?”Big difference.

.png)

