Careeroza
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 testExample 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