Kotlin Parameterized Tests
When writing tests in Kotlin, you'll often find yourself creating similar test cases with different input values. This is where parameterized tests come in — they allow you to run the same test logic against multiple sets of inputs, making your test code more concise and maintainable.
What Are Parameterized Tests?
Parameterized tests let you execute the same test multiple times with different arguments. Instead of writing separate test functions for each input scenario, you define a single test that runs with various input parameters.
The benefits include:
- Less code duplication: Write the test logic once and reuse it
- Better test coverage: Easily test with many input variations
- Improved readability: Test cases are more structured and organized
- Easier maintenance: When test logic changes, you only need to update it in one place
Getting Started with JUnit 5 Parameterized Tests
JUnit 5 is one of the most popular testing frameworks for Kotlin and offers excellent support for parameterized tests.
Setting Up Dependencies
First, add the required dependencies to your build.gradle.kts
file:
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2")
testImplementation("org.junit.jupiter:junit-jupiter-params:5.9.2")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2")
}
Basic Parameterized Test
Let's start with a simple example — testing a function that checks if a number is even:
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
class NumberTests {
fun isEven(number: Int): Boolean = number % 2 == 0
@ParameterizedTest
@ValueSource(ints = [0, 2, 4, 100, 1000])
fun `should return true for even numbers`(number: Int) {
assertEquals(true, isEven(number))
}
@ParameterizedTest
@ValueSource(ints = [1, 3, 5, 99, 1001])
fun `should return false for odd numbers`(number: Int) {
assertEquals(false, isEven(number))
}
}
Here, the @ParameterizedTest
annotation marks a method as parameterized, and @ValueSource
provides the test values. Each value is passed one by one to the test method.
Parameter Sources in JUnit 5
JUnit 5 offers several ways to provide parameters:
1. ValueSource
Provides a simple array of literal values:
@ParameterizedTest
@ValueSource(strings = ["apple", "banana", "cherry"])
fun `test with string parameters`(fruit: String) {
assertTrue(fruit.length > 3)
}
2. CsvSource
Supplies multiple parameters per test invocation using CSV format:
@ParameterizedTest
@CsvSource(
"apple, 5",
"banana, 6",
"cherry, 6"
)
fun `test fruit name lengths`(fruit: String, length: Int) {
assertEquals(length, fruit.length)
}
3. MethodSource
References a method that provides the test arguments:
@ParameterizedTest
@MethodSource("fruitProvider")
fun `test fruits from method source`(fruit: String) {
assertTrue(fruit.length > 3)
}
companion object {
@JvmStatic
fun fruitProvider() = Stream.of("apple", "banana", "cherry")
}