Unit Tests with JUnit 5

Setup

// build.gradle.kts (JVM / backend module)
dependencies {
    testImplementation(platform("org.junit:junit-bom:5.11.3"))
    testImplementation("org.junit.jupiter:junit-jupiter")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
    testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
    testImplementation("io.mockk:mockk:1.13.13")
    testImplementation("app.cash.turbine:turbine:1.2.0")
}

tasks.test { useJUnitPlatform() }

Note: Android modules use JUnit 4 by default (testImplementation("junit:junit:4.13.2"), @Rule). Everything below about coroutines and MockK works the same with JUnit 4.

A First Test

Kotlin lets you name tests with backticks, so a test reads like a sentence. Use the Arrange / Act / Assert pattern.

class PriceCalculator {
    fun finalPrice(mrp: Int, discountPercent: Int): Int {
        require(discountPercent in 0..90) { "invalid discount" }
        return mrp - mrp * discountPercent / 100
    }
}

class PriceCalculatorTest {
    private val calc = PriceCalculator()

    @Test
    fun `applies percentage discount`() {
        val price = calc.finalPrice(mrp = 1000, discountPercent = 15)   // act
        assertEquals(850, price)                                        // assert
    }

    @Test
    fun `rejects discount above 90 percent`() {
        val e = assertThrows<IllegalArgumentException> { calc.finalPrice(1000, 95) }
        assertEquals("invalid discount", e.message)
    }

    @ParameterizedTest
    @CsvSource("100, 0, 100", "100, 50, 50", "999, 10, 900")
    fun `table of cases`(mrp: Int, discount: Int, expected: Int) {
        assertEquals(expected, calc.finalPrice(mrp, discount))
    }
}

Example

Run the tests with Gradle:

./gradlew test

Example output

> Task :test

PriceCalculatorTest > applies percentage discount() PASSED
PriceCalculatorTest > rejects discount above 90 percent() PASSED
PriceCalculatorTest > table of cases(int, int, int) > [1] 100, 0, 100 PASSED
PriceCalculatorTest > table of cases(int, int, int) > [2] 100, 50, 50 PASSED
PriceCalculatorTest > table of cases(int, int, int) > [3] 999, 10, 900 PASSED

BUILD SUCCESSFUL in 4s