You may be wondering, “why not use production code in tests?” Sometimes it might not be possible — like calling an Android framework class in unit tests — or sometimes we don’t want to. For example, if we want to test out a retrofit network call that transfers money from one account to another, we don’t want to transfer money every time the test is called. In those cases we replace the production code with alternative implementations for testing purposes and these are called ‘Test Doubles.’
There are various types of test doubles; in this article, we will take a look at 3 commonly used ones: Fakes, Mocks, and Stubs.
Examples listed in this article are written in Kotlin, but the concepts are transferable. While it is possible to use our own implementation for providing the mocking and stubbing logic, in this article we’ll be using a mocking framework called
mockito-kotlin to make generating test doubles easy.
Fakes have working implementation but have alternative code compared to the production; sometimes it might be much simpler compared to production code.
An example for this case is using a fake datasource instead of
touching the actual database or network or performing disk operations.
In the following example we are making a
that can be used to replace the production version in tests. This
implementation is simpler compared to the production version which would
have to deal with database. This is especially useful in
instrumented/integration tests where you might be testing the entire
implementation of the datasource.
Mocks are objects that expect certain calls to be made. They will throw an assertion error when they don’t receive those calls that are expected or if they receive a call that is not expected.
We use mocks when we don’t want to invoke the production code but want to check if the action is called or check how many times a certain action is performed. This is especially useful when you cannot run the production code in tests or if you want to avoid running the production code in tests but still verify that the methods are invoked.
In the following example we have a
UserPaymentsRepo that takes in
PaymentsApi . When we send a payment to the user, we expect to call the
Stubs are objects that lets you control a methods behaviour in a test. They are usually placed at the top of the test.
An example for this case is returning predefined data whenever a database method is called. We are doing this to avoid calling the database in tests or testing various database cases.
Let’s say we are making a social networking app and we want to get list of starred contacts for the user.
Instead of making the database call, we provide a stub that returns a predefined list of starred contacts. Then we can assert that we received the same contacts when we are calling
When to use what
Here is how I decide when to use Fakes, Stubs, Mocks.
Fakes: To provide alternate implementation of the production code that is independent of the system and can be tested quickly.
Mocks: To mock the production code and also to verify all the actions are performed/not to be performed in the test case.
Stubs: To have a predefined response for the calls made during the test case.
If you'd like to read more, these are some great resources to bookmark:
TestDouble: Martin Fowler
Mocks Aren’t Stubs: Martin Fowler
Introduction to Test Doubles and Dependency Injection: Google Codelabs
Fundamentals of Testing: Android Developers
If the Obvious Way makes sense to you, let us buy you some (virtual) breakfast. We’ll tell you more about the work that we do, give you the lowdown on life at Obvious, and answer any questions that you might have about engineering or working here. Or jump straight in, and apply to join our team!