Blog post

🧪 Unit Testing: What to Mock and What Not To?

Neha Saggam

-
June 6, 2025
Testing
Unit Testing
Mocking
Jest
Javascript

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; } }

❓ 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 (); });

✌️ 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.

Related Blog Posts