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