Mocking with MockK

Why MockK

MockK is a mocking library written for Kotlin. Unlike Mockito it handles final classes, objects, extension functions and suspend functions out of the box.

MockKMeaning
mockk<T>()strict mock: un-stubbed calls throw
mockk<T>(relaxed = true)returns default values for everything
every { ... } returns xstub a normal function
coEvery { ... } returns xstub a suspend function
verify { ... } / coVerify { ... }check a call happened (exactly = 1, atLeast...)
slot<T>() + capture(slot)capture the argument for assertions
spyk(obj)real object with some functions stubbed

Example

class CheckoutServiceTest {
    private val payments = mockk<PaymentGateway>()
    private val orders = mockk<OrderRepository>(relaxed = true)
    private val service = CheckoutService(payments, orders)

    @Test
    fun `saves order after successful payment`() = runTest {
        coEvery { payments.charge(any(), 799) } returns PaymentResult.Success("pay_123")
        val saved = slot<Order>()
        coEvery { orders.save(capture(saved)) } just Runs

        service.checkout(userId = 7, amount = 799)

        coVerify(exactly = 1) { payments.charge(7, 799) }
        assertEquals("pay_123", saved.captured.paymentId)
    }

    @Test
    fun `does not save order when payment fails`() = runTest {
        coEvery { payments.charge(any(), any()) } throws PaymentDeclinedException("insufficient funds")

        assertThrows<PaymentDeclinedException> { service.checkout(7, 799) }
        coVerify(exactly = 0) { orders.save(any()) }
    }
}

Tip: Prefer fakes (small hand-written implementations) for repositories you use in many tests, and mocks for verifying one interaction (was the payment charged exactly once?). Over-mocking makes tests break on every refactor.