In mid 18th century , there was a popular dish in England called the green turtle soup, obviously prepared with sea turtles meat. This soup was very expensive to prepare knowing that the turtles meat was rare. So it was sometimes substituted with beef organs and called the Mock Turtle Soup.
Lewis Carroll introduced in his popular book ‘Alice’s Adventures in Wonderland’ a character called the Mock Turtle. he was supposed to be the animal used in mock turtle soup.
“Once,” said the Mock Turtle at last, with a deep sigh, “I was a real Turtle.” (Alice In Wonderland, Lewis Carroll)
In 2001 Tim Mackinnon, Steve Freeman and Philip Craig wrote a paper about unit tests called Endo-testing: unit testing with mock objects. this was the first time the word Mock was used to describe dependencies that are not real in unit tests in order to isolate component and make sure it behaves as expected in all possible cases.
In 2007 Gerard Meszaros referred to those components as Test doubles in his book xUnit test patterns. A test double can be any component we eventually use to satisfy an object dependencies.
I actually prefer to use Test doubles over Mocks since a Mock is a single case of test doubles, while this last describes the whole family. as we will see below.
According to Meszaros, there are too much confusion and inconsistency around the terminology of test doubles among the development community. In a way that many terms are used to describe the same thing and vis versa.
Then he suggested a vocabulary to use for each type of test doubles, a vocabulary that gained a lot of popularity and became a standard,
Why it’s important ?
Using the type of test doubles is very important to have some unit tests that are easy to understand, to have unit tests that follows conventions.
This is also important in order to choose the appropriate test double for your unit test. because not doing so may have some nasty side effects as we will see further in this article.
Important terminology :
SUT : Stands for “System under test”, which refers to the component that the unit tests are about, For instance : the class we are testing .
A dummy is a dependency that simply does not matter for the unit test. Usually it’s an object that will have no influence on the test results. It’s actually only used to fill the dependencies. Sometimes passing a null is way enough.
We use a dummy to make the compiler stop crying about missing dependencies.
A dummy also allows to clearly see objects and values that are (or not) used during a unit test.
Usually creating a dummy does not require a Framework or tool. since it’s only an empty implementation.
For example you have a dependency that you use to log events. This is something totally irrelevant to the test output. then we can use a dummy logger.
As a general rule, a dummy should do nothing. and return as close to nothing as possible.
This is probably the most common case of test doubles. A Stub provides predefined answers to indirect inputs the SUT will need during unit tests.
It can be created with a tool that will generate it based on the class type. Or it can be manually written as a set of hardcoded values that matches your test case.
We know we need a Stub when we need to control the indirect inputs of our SUT, While we don’t want to have any verification logic on it.
Here for example we need to create a test double for a user account manager dependency. which will return us some hardcoded values we will define depending on the test case.
A spy is a special type of test doubles, that remembers how and when it was called. It literally spies all the informations we can’t directly get from the SUT, which allows to capture indirect outputs.
A Spy can also return some hardcoded values like Stubs, but with a the key difference. It does not perform any verification, it only gets indirect outputs out of the SUT so that we can verify them later.
Usually creating a spy does not require a framework or tool.
Here for instance we have a sendEmail method which returns nothing, which is called inside OrderController.
How to make sure that sendEmail was called when testing OrderController? Knowing that sendEmail makes not output.
The answer is to create an EmailServiceSpy. which will record how many times sendEmail was called. so that we can use it as a test double when Testing OrderController.
Like a Spy, a Mock allows also to remember things about how it was called. but it has an extra feature which gives it it definition.
A mock knows what is the right behaviour. a mock knows what should take place.
In other words, a spy only gets out the values we need for our tests. A mock also verifies that those values matches what is expected.
Like stubs mocks might be created manually or generated using a tool.
Using the same example above here we used a mock with a verification method, that returns a boolean indicating whether send email was called the right number of time.
Mock or Spy ?
It’s important to mention, as a general rule, a Mock should be the option to go for rather than Spies. we only use a spy when it’s not possible or complicated to use a mock.
Or for instance your code core needs some refactoring to be cleanly testable. then you can use spies.
Or let’s say you have a function callback as input for your SUT. and it’s not possible to mock it with the framework you are using.
A fake is a simplified implementation of a more complex dependency.
We usually use it when the SUT depends on another component which holds states.
A good candidate for a fake is a component that cannot be replaced with only static values. Hence a Fake should have some logic on it.
Let’s say you have a database dependency. obviously we will not be using a real database for our unit tests. then we can create a fake database that will store data in an array to simulated a database under unit tests
Note that a using a “OnMemory” database for unit tests is a kind of fakes also.
In the above example we did a FakeUserDefaults which is a subclass of the real UserDefaults , it overrides the set and objectForKey methods by using a dictionary to store and fetch values.
It’s important to note that a Fake logic can grow along with the real object. which may become complicated to maintain at a certain level. This is why it’s advised to use TDD while making fakes to keep them under control.
In a real project, you might be using some library to create a some types of test doubles. i did the examples without libraries in purpose in order to understand better the concepts.
There is an other reason which is because a lot of mock libraries doesn’t respect those standard, which brings more confusion about the topic.
Regardless of the tool or language you are using , the important is to understand how and when to use the right test double.
Thank you for reading 😃 !!
Originally published in my blog.