kotlinintermediate

Testing with MockK Framework

Mock dependencies in Kotlin tests with MockK: relaxed mocks, verify, coEvery, and slot captures.

kotlin
import io.mockk.*
import io.mockk.coEvery
import io.mockk.coVerify
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.*

// Interfaces
interface UserRepository {
    fun findById(id: Int): User?
    fun save(user: User): User
    fun findAll(): List<User>
    suspend fun findByIdAsync(id: Int): User?
}

interface EmailService {
    fun send(to: String, subject: String, body: String)
}

data class User(val id: Int, val name: String, val email: String)

class UserService(
    private val repo: UserRepository,
    private val emailService: EmailService
) {
    fun getUser(id: Int): User = repo.findById(id)
        ?: throw NoSuchElementException("User $id not found")

    fun createUser(name: String, email: String): User {
        val user = User(0, name, email)
        val saved = repo.save(user)
        emailService.send(email, "Welcome!", "Hello $name")
        return saved
    }
}

class UserServiceTest {
    private val repo = mockk<UserRepository>()
    private val emailService = mockk<EmailService>(relaxed = true)
    private val service = UserService(repo, emailService)

    @Test
    fun `getUser returns user when found`() {
        val user = User(1, "Alice", "alice@test.com")
        every { repo.findById(1) } returns user

        val result = service.getUser(1)

        assertEquals("Alice", result.name)
        verify(exactly = 1) { repo.findById(1) }
    }

    @Test
    fun `getUser throws when not found`() {
        every { repo.findById(99) } returns null

        assertThrows(NoSuchElementException::class.java) {
            service.getUser(99)
        }
    }

    @Test
    fun `createUser saves and sends email`() {
        val slot = slot<User>()
        every { repo.save(capture(slot)) } answers {
            slot.captured.copy(id = 1)
        }

        val result = service.createUser("Bob", "bob@test.com")

        assertEquals(1, result.id)
        assertEquals("Bob", result.name)

        verify { repo.save(any()) }
        verify {
            emailService.send(
                "bob@test.com",
                "Welcome!",
                "Hello Bob"
            )
        }
    }

    @Test
    fun `findAll returns all users`() {
        val users = listOf(
            User(1, "Alice", "a@t.com"),
            User(2, "Bob", "b@t.com")
        )
        every { repo.findAll() } returns users
        every { repo.findAll() } returnsMany listOf(users, emptyList())

        assertEquals(2, repo.findAll().size)
        assertEquals(0, repo.findAll().size)

        verify(exactly = 2) { repo.findAll() }
    }
}

Use Cases

  • Unit testing with mocked dependencies
  • Verifying interaction patterns
  • Capturing arguments for assertions

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.