Nothing should ever be mocked. Period. If you don't agree you likely don't understand many things. Think about why mocks exist in the first place. Mocks exist for things that can't be tested. What you are doing is creating something completely new in place of that thing that can't be tested and testing that new thing instead. Utterly pointless. If it can't be tested, you can't test it period. It's like saying drugs can't be tested on humans, so you create a plastic dummy in the shape of a human to test the drug on instead. Come on man.

There are books, there are experts, there are people with years of experience who think they know what they're doing but the minute I see a mock in a code base which is probably 99% of what's out there I already know that the people who designed the system don't know what they're doing.

Nothing. Ever. Needs. To. Be. Mocked. Many of you are thinking you know better. You don't. Mocking is bad. Allow me to explain.

There are two parts of your code. Code that can be unit tested and code that can't be unit tested.

Code that can't be unit tested is simple. Any code that has to touch IO can't be unit tested. Period. Any code that doesn't touch IO can be unit tested. It's that simple.

Why do people mock? Because people write systems that are too tightly integrated with IO.

Imagine this function:

function addTwo(x: socket) -> number{
return socket.get_one_numer() + 2;
}

Now you have a function that adds 2 to a number. But in order for it to be unit tested you have to Mock the socket. The socket is a parameter polluted with IO. If you have that parameter touch any part of your code then all of that code cannot be unit tested anymore and you have to mock that socket if you want to regain unit testing functionality.

What's the simple way to fix this? Easy Keep ALL IO segregated from the rest of your code. Keep IO functions and methods super small. Do not inject IO polluted objects into other parts of your code. It's trivial:

function addTwo(x: number) -> number {
return x + 2;
}

function getNumber(void) -> number {
return socket.get_one_number();
}

There. No mocks. addTwo is a function that can be unit tested and getNumber is an IO function that can NEVER be unit tested. That's it. No need to mock it.

There are two types of IO functions. Input and Output. Inputs have void parameters. Outputs have void return values. These are the functions that can't be unit tested. If you keep these functions super small and tiny, guess what? Most of your code can be tested with unit tests and you're golden.

Instead what you'll see throughout your career is typically this garbage:

class RandomObject(int param1, Socket paramSocket, IOService paramIOService, LogService logService){};

or some other overly complicated, over engineered structure that necessitates Dependency injection or some other garbage pattern that forces people to mock things to test.

Think about it. Every single method you put in that class cannot be unit tested. By using this stupid pattern you pollute that entire class file with IO and nothing can be unit tested unless you mock the socket and/or the IO service.

The problem is, this pattern even though it's so obviously detrimental is used practically everywhere because the complexity of the pattern makes it seem modular and "advanced" when really it's just bad.

Additionally I neglected to mention that it's not only IO. But overly complicated logic sometimes is mocked as well. To that I say it's the same problem as IO. If you find yourself mocking overly complicated logic to test some portion of your code it means that portion of your code is too tightly integrated with the rest of the universe. You need to loosen the coupling.