thecodex.expert · The Codex Family of Knowledge
Kotlin

Testing

kotlin.test isn’t a separate testing framework — on the JVM, it’s a thin, Kotlin-friendly wrapper that runs on JUnit underneath, while staying source-compatible across Kotlin’s other platforms too.

Kotlin 2.1 kotlin.test or Kotest Last verified:
Canonical Definition

kotlin.test provides @Test and assertion functions (assertEquals, assertTrue, assertFailsWith) with Kotlin-friendly naming, delegating to JUnit as its actual test runner on the JVM — the same underlying JUnit annotations and lifecycle still apply, just accessed through Kotlin-idiomatic wrappers, and the same API surface is source-compatible on Kotlin/Native and Kotlin/JS too. Kotest is a separate, more expansive third-party framework offering several distinct testing styles (a Given-When-Then BDD style, a simple function-based style, and others) plus a fluent assertion DSL (result shouldBe 5) that many find more readable than JUnit's assertEquals(5, result) argument order.

A basic test with kotlin.test

assertFailsWith checks that calling the lambda throws the given exception type — a cleaner, more Kotlin-idiomatic way to express "this should throw" than JUnit's assertThrows on its own.

KotlinCalculatorTest.kt
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith

class CalculatorTest {
    @Test
    fun addsTwoNumbers() {
        val calc = Calculator()
        assertEquals(5, calc.add(2, 3))
    }

    @Test
    fun throwsOnDivideByZero() {
        val calc = Calculator()
        assertFailsWith<ArithmeticException> {
            calc.divide(1, 0)
        }
    }
}

The same test with Kotest's fluent style

shouldBe reads closer to natural language than assertEquals's argument-order convention, and Kotest's StringSpec style lets each test's description double as its actual name in test output.

KotlinCalculatorTest.kt
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe

class CalculatorTest : StringSpec({
    "adding two numbers" {
        Calculator().add(2, 3) shouldBe 5
    }
})

Testing coroutines: runTest

runTest (from kotlinx-coroutines-test) runs a suspending test body while automatically fast-forwarding through any delay() calls, so a test involving real coroutine timing doesn't actually have to wait in real time.

KotlinCoroutineTest.kt
import kotlinx.coroutines.test.runTest
import kotlin.test.Test

class DataLoaderTest {
    @Test
    fun loadsData() = runTest {   // suspending test body, delay() calls fast-forwarded
        val result = loadDataAsync()
        assertEquals("data", result)
    }
}

Sources

1
JetBrains. kotlin.test API reference, kotlinlang.org/api/core/kotlin-test, and Kotest documentation, kotest.io.