I’m honestly confused about the goal of mocking certain functions when unit testing my app. I’ve seen articles suggesting I should mock everything I test, but also others suggesting I should avoid mocking as much as possible.
I need some help understanding the decision behind to mock or not parts of my code.
Let’s say I have the following function:
export const numberFormat = (num) => {
return new Intl.NumberFormat('en-EN', {
style: 'decimal',
maximumFractionDigits: 2
}).format(num)
}
And I decided to test it by importing the literal function, like that:
import { test, expect } from 'vitest'
import { numberFormat } from './numberFormat.js'
const numValue = 1000.12345678
test('number is formatted', () => {
expect(numberFormat(numValue)).toBe('1,000.12')
})
Would this be wrong? I’m quite literally just formatting a number, why should I mock this function?
2
Answers
When we are to plan or define unit tests, then we want to separate the things we are to test into atomic and very simple units. If you have an
f
function, then these are the parts you may wonder about regarding it:f
f
is callingf
may be used alikeIf you wonder about the algorithm of
f
, then your units would mock the functionsf
is calling with the idea that okay, let’s assume that those functions were executed and their result was this and this and this. Wouldf
perform well in that scenario? So in this case you mock the functionsf
is calling but testf
.If, on the other hand you are interested about the functions
f
is calling, then you need to differentiate between the use-cases of such functions and test them without mocking them.Finally, if you are interested about
f
‘s usages and notf
itself, then you mockf
and test its use, with the idea off
behaving in certain manners and how its usage would respond to this situation.So, whenever you take
f
into account, the question is what aspect off
are you interested about in that specific test. Is it some functionf
is calling? Orf
itself? Or its usage? And in order to decide whether to mock or not to mockf
you will need to answer these questions.As a general rule, there are three groups of components that need to be replaced in tests with test doubles:
The reasons why such components are replaced with test doubles:
Replacing with test doubles a component that does not belong to any of the groups above is a smell. It usually signals a component that has too many dependencies (and hidden dependencies) and is difficult to create.