15 jun 2024
Understanding Test Doubles: Comprehensive Guide for Beginners
Testing is an essential part of software development, ensuring that our code works as expected and helping catch bugs early in the development process.
One concept that's vital in testing, especially in Test Driven Development (TDD), is the use of test doubles. If you're new to this term, don't worry - this post will break it down for you with explanations and examples.
What are Test Doubles?
Test doubles are objects that stand in for real components in your system during testing. They support good Object-Oriented design by guiding the discovery of a coherent system of types within a codebase.
Let's explore 5 different types of test doubles with an example around this interface:
Dummy
A dummy object is used when you need to pass it into something but you don't care about its value or behavior. For example: As a part of a test, when you must pass an argument, but you know the argument will never be used.
Usage Example
Stub
A stub provides predefined responses to method calls, useful when you want to control the environment and test specific scenarios.
Usage Example
Suppose you need to test a part of your system that requires a logged-in user, but you don't want to re-test the login process itself. In this scenario, you should use a Stub to simulate a successful login.
Stubs help you remove unnecessary coupling by isolating the component being tested.
Spy
A spy is similar to a stub but with added capabilities to record information about how it was called.
Usage Example
Spies can verify that certain methods were called, how often, and with what arguments.
So a Spy, spies on the caller.
You can use Spies to see inside the working of the algorithms you are testing.
But be careful! The more you spy, the tighter you couple your tests to the implementation. And that leads to fragile tests.
Mock
A mock is a more sophisticated spy that can set expectations on its behavior and verify them.
It looks like we moved the assertion from the test into the verify method of the mock, right? Because Mocks know what they are testing.
Usage Example
The main point about the Mock is that it is testing behavior.
The mock is not so interested in the return values of functions. It's more interested in what function were called, with what arguments, when, and how often.
A mock is always a spy, with the difference that the mock knows what behavior to expect.
Fake
A fake is a working implementation that is used for testing purposes. It has business logic but is simpler than the real system.
In this example everybody named "Bob" will be authorized.
It's important to know that none of the other test doubles we've talked about so far have business behavior, but Fakes do have it. So fakes are different at a fundamental level.
We can say that a mock is a kind of spy, a spy is a kind of stub, and a stub is a kind of dummy. But a fake isn't a kind of any of them. It's a completely different kind of test double.
Usage Example
Take care about the fact that Fakes can get extremely complicated. So complicated they need unit tests of their own. At the extremes the fake becomes the real system.
Test doubles, or just mocks?
It's worth noting that nowadays, many developers tend to blur the lines between different types of test doubles, often referring to all of them simply as "mocks".
This is largely due to the prevalence of mocking libraries, which provide versatile tools capable of acting as dummies, stubs, spies, or mocks depending on the way you use them.
In the future, I look forward to write another post about how to use some of my favorite mocking libraries with practical examples. Stay tuned!
Conclusion
Test doubles are a powerful tool in your testing toolbox. By understanding and using different types of test doubles you can write more effective tests and improve the quality of your code.
Remember, each type serves a specific purpose, so choose the one that best fits your testing needs.
Inspiration
This post was inspired by a conversation documented by Uncle Bob on the topic of test doubles, as I found his insights to be very valuable when I was learning about testing.
I aimed to distill this knowledge into a concise guide with brief explanations and practical examples.
Hope you find it helpful!
THANKS FOR READING 🥳
If you have any questions or feedback, you can contact me via Twitter or LinkedIn.
If you liked the post, you can share it with more developers who might find it useful.
Thank you! 🙌
Go back