profile picture

To mock or not to mock

How to escape the mocking hell

January 11, 2021 - 783 words - 4 mins Found a typo? Edit me
software mocking testing design

blog-cover

Mocking is useful, but “what to mock” usually turns out to be a bit more complicated than expected if you don’t treat this carefully.

How to escape the mocking hell

What is actually happening when we create a mock? Which types of mocks are there? Is mocking good or bad? Well, as always, everything depends on the context. And here we will consider some of the main situations about when to mock and when not to mock, but especially why.

What happens when you mock something?

First, we should define what is a mock:

In a unit test, mock objects can simulate the behavior of complex, real objects and are therefore useful when it is impractical or impossible to incorporate a real object into a unit test.

Mocking makes sense in a unit testing context. An integration test should go through the real implementation checking the integration between multiple units, which are even allowed to talk to the DB or File IO: infrastructure code. Therefore we should agree that a unit test is a fast and deterministic test that doesn’t rely on external dependencies and doesn’t require any special context to run.

Mock objects meet the interface requirements. In consequence, they allow us to write and unit-test functionality without calling complex underlying or collaborating classes.

A mock is a test double that stands in for real implementation code during the unit testing process. It is also capable of producing assertions about how it was manipulated by the test subject during the test run.

I strongly recommend you to read this post if you want to get into the details of why Mocking is a code smell (Topics like these: What is a mock? What is a unit test? What is test coverage? What is tight coupling? What causes tight coupling? What does composition have to do with mocking? How do we remove coupling? and more!)

The problem with mocking

When you mock you are overriding the logic of the mocked class. The real logic is getting hidden behind the scenes and there is actually where bugs love to live. Consider that:

Alternatives to mocking

“Are you saying that mocking is bad and we shouldn’t mock?!” No.

It depends on what you are “overriding”.

It depends on the context of the logic and where that logic belongs.

Is it part of your business domain logic? Then you shouldn’t mock it but instantiate it.

Is it part of any infrastructure dependency like DB connection, IO file system, Network, or any external service that has nothing to do directly with your business domain? Then mock it using abstractions/interfaces.

The interface should be the contract between your business domain logic and its external infrastructure dependencies. Imagine how easy it would be to unit test your domain logic by instantiating it and calling their methods with different arguments expecting different inputs under your entire control.

Some tricks

When you are writing a unit test:

Mock interfaces. Instantiate concrete classes.

“Excessive use of mocks leads to legacy code.” — Philippe Boargau

How can we avoid excessive mocking?

blog-img


References