Introduction to Fakes in TDD with Kotlin

Introduction to Fakes in TDD with Kotlin

Welcome to our lesson on using Fakes as test doubles in Test Driven Development (TDD) with Kotlin, JUnit, and Mockito. In this lesson, you'll explore how fakes can streamline your testing by simulating real-world components. Our journey so far has exposed you to various test doubles like dummies, stubs, spies, and mocks. Now, we'll dive into fakes, which enable you to create realistic implementations that mirror complex dependencies, making your tests more robust and reliable. As always, we'll practice the TDD cycle: Red, Green, Refactor, as we see how fakes fit into our testing strategy.

Code Example and Walkthrough: Implementing an In-memory Fake Repository

Let's see how to implement a simple fake: an InMemoryUserRepository. This serves as a stand-in for a real database repository, providing controlled behavior for our tests.

Create a class InMemoryUserRepository.kt:

class InMemoryUserRepository : IUserRepository {
    private val users = mutableMapOf<String, User>()
    private var currentId = 1

    private fun generateId(): String = currentId++.toString()

    override fun create(userData: User): User {
        val user = User()
        user.id = generateId()
        user.email = userData.email
        user.name = userData.name
        user.createdAt = LocalDateTime.now()
        users[user.id] = user
        return user
    }

    override fun findById(id: String): User? = users[id]

    override fun findByEmail(email: String): User? {
        return users.values.firstOrNull { it.email.equals(email, ignoreCase = true) }
    }

    override fun update(id: String, data: User): User? {
        val existing = users[id]
        existing ?: return null

        data.email?.let { existing.email = it }
        data.name?.let { existing.name = it }
        users[id] = existing
        return existing
    }

    override fun delete(id: String): Boolean = users.remove(id) != null

    override fun findAll(): List<User> = users.values.toList()

    override fun clear() {
        users.clear()
        currentId = 1
    }
}

Explanation:

  • We create an in-memory store for users using a mutable map.
  • Each function simulates typical database operations such as creating and finding users.
  • The clear method ensures data isolation between tests, a crucial feature for repeatable outcomes.

By having a controlled data store, we make sure our tests are focused on business logic and not dependent on an external database. Fakes often mimic the behavior of real components, providing a safe and predictable testing environment without the complexity of external systems.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal