Mocks, fakes and stubs: the stunt doubles of testing

--

Many folks in our industry are familiar with unit testing, and practice it daily. Some folks get to the extreme of considering tests more important than production code, while others think it’s just a waste of time, but unit tests have saved my bacon more times than I care to admit. They’re a great way to ensure correctness, and adherence to business rules.

You may have been writing tests for a long time now, and yet not ever use one of the best tools there are: mocks, fakes and stubs. We’ll see what they are, why they’re useful, and what’s the difference between each other.

Benefits of unit tests

People vector created by pch.vector

First of all, if you don’t already include testing in your development cycle, you should. The additional effort involved in writing and maintaining tests is more than paid back in peace of mind.

Expressing a requirement in a unit test will not only help you articulate its edge cases, but also inform you when further changes break expectations or cause regressions. Doing any significant refactoring without a comprehensive test suite is like free climbing: you may get away with it, and some folks love the feeling, but it’s hardly something I’d recommend to the faint of heart.

Unit tests are also a great way to express the expected behaviour and contract of a piece of code. Unlike comments and external documentation, they cannot get out of date: any breaking change in the SUT (System Under Test; in this case the unit that is being tested) will cause well-written tests to go red and immediately alert the team.

Integration tests and validation tests are also very important tools to ensure the correctness of software we write, but in this post we’re focusing mostly on unit testing.

There’s plenty to be said about testing and its benefits[1], but that’s beyond the scope of this article. I will leave it as an exercise to the reader to read up further on the topic — there are plenty of excellent articles and talks out there on the subject.

Doubles are here to help

In unit tests, you often find yourself having to deal with dependencies of the SUT. For example, testing an inventory management object may require an instance of InventoryRepository, which in turn depends on a Database, to save data to and read from. Since unit tests should never involve any system outside of the SUT itself, we find ourselves in a pickle: how do we test the functionality of our InventoryManager class without a real database?

class InventoryManager(private val repository: InventoryRepository) {

fun totalStockCount(): Int =
repository.getItems().sumBy { it.stockCount }

fun removeItem(sku: Int, count: Int = 1) {
repository.removeItem(sku, count)
}

fun getItemStockCount(sku: Int): Int? =
getItem(sku)?.stockCount

private fun getItem(sku: Int): InventoryItem? =
repository.getItems().find { it.sku == sku }
}
interface InventoryRepository { fun getItems(): List<InventoryItem>

fun removeItem(sku: Int, count: Int = 1)
}
class DatabaseInventoryRepository(
private val database: Database
): InventoryRepository {
// ...
}

You need a so-called test double. There are three main kinds of test double, each with its strengths and weaknesses. Note that, in order to make the most of doubles, a well organised codebase with well thought-out abstractions will go a long way. In general, anything that should be swappable at test time with some double should be an interface, and not a concrete implementation.

Curious? Want to continue reading this article? You can find the full post over on my blog:

I’m trying to gain more control over what I publish and where, so you can only find full versions of my posts on my Ghost-hosted blog. I’ll keep cross-posting teasers here on Medium to get visibility, but the full articles are going to only appear over there. All the previous articles from Medium have been migrated over — don’t worry, they’re still available here, and as always, they’re free and ad-free. Bonus: articles look better over there, as I have fewer limitations than I do here on Medium.

--

--

"It depends" 🤷‍♂️ - UXE on Android Studio at Google. A geek 🤓 who has a serious thing for good design ✨ and for emojis 🤟 Personal opinions only 😁