Testing
|
This section documents Kotlin 2.4.x on the JVM, as published at kotlinlang.org, which is the reference these pages are written and verified against. This content was generated with the assistance of AI and should be verified against kotlinlang.org before being relied on in production. This section’s bibliography lists the reference material consulted while preparing these pages. |
Kotlin testing builds directly on the JVM testing ecosystem covered in
Testing with JUnit 5 and Mockito — JUnit 5 runs Kotlin test classes with no
changes needed — plus two Kotlin-specific additions: kotlin.test and MockK, and coroutine-aware test support.
kotlin.test
kotlin.test is a thin, multiplatform-friendly facade over whichever underlying test framework is on the
classpath (JUnit 4, JUnit 5, or a JS/Native test runner for a Kotlin Multiplatform project) — useful when test
code itself needs to stay platform-agnostic, though a JVM-only project commonly just uses JUnit 5’s own
org.junit.jupiter.api.Assertions directly instead:
import kotlin.test.Test
import kotlin.test.assertEquals
class CalculatorTest {
@Test
fun addsTwoNumbers() {
assertEquals(5, Calculator().add(2, 3))
}
}
JUnit 5 with Kotlin
Backtick-escaped test names (Lexical Structure and
Style) are the single most visible Kotlin-specific idiom in test code — a descriptive sentence as the method
name, with no separate @DisplayName needed:
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertThrows
class AccountTest {
@Test
fun `withdraw reduces the balance`() {
val account = Account(100)
account.withdraw(30)
assertEquals(70, account.balance())
}
@Test
fun `withdrawing more than the balance throws`() {
val account = Account(100)
assertThrows(IllegalStateException::class.java) {
account.withdraw(999)
}
}
}
@ParameterizedTest, @BeforeEach/@AfterEach, and every other JUnit 5 Jupiter feature from
Testing with JUnit 5 and Mockito apply unchanged.
MockK
MockK is a mocking library built for Kotlin’s language features (top-level/extension
functions, coroutines, object singletons) that Mockito — built for Java — cannot mock directly:
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
class OrderServiceTest {
@Test
fun `totals an order`() {
val pricing = mockk<PricingClient>()
every { pricing.unitPrice("sku-1") } returns 250
val service = OrderService(pricing)
val total = service.total("sku-1", quantity = 3)
assertEquals(750, total)
verify(exactly = 1) { pricing.unitPrice("sku-1") }
}
}
MockK can also mock a suspend function directly (coEvery { … } returns … / coVerify { … }) and, with
mockkObject, a Kotlin object singleton — both scenarios Mockito has no native way to handle.
kotlinx-coroutines-test for Testing Suspend Functions and Flows
Testing a suspend function or a Flow (Coroutines Basics,
Flows) needs a coroutine to call it from, plus control over virtual time so
a test with delay(5_000) inside it does not actually take five seconds to run. runTest provides both:
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.delay
@Test
fun `fetchUser returns the expected user`() = runTest {
val result = fetchUser(1) // "runTest" provides a TestScope to call suspend functions from
assertEquals("Ada", result.name)
}
@Test
fun `retries after a delay`() = runTest {
val start = currentTime // virtual time, not wall-clock time
delay(5_000) // completes "instantly" -- runTest auto-advances virtual time
assertEquals(5_000, currentTime - start)
}
@Test
fun `emits the expected values`() = runTest {
val values = numbers().toList() // collecting a Flow into a List for straightforward assertions
assertEquals(listOf(1, 2, 3), values)
}
runTest is the direct, coroutine-aware replacement for runBlocking in test code — using plain runBlocking
in a test with real delay() calls would make the suite slow for no benefit, since nothing about the delay
itself is under test.
See Also
-
Testing with JUnit 5 and Mockito — the JUnit 5 foundation this page builds on.
-
Coroutines Basics and Flows — what
runTestis actually exercising. -
Lexical Structure and Style — backtick-escaped identifiers, used throughout this page’s test names.