In March 2021, we announced the open source release of TestParameterInjector: a simple but powerful parameterized test runner for JUnit4. In September 2022, we followed up with JUnit5 support, bringing our framework to developers who had moved on to the Jupiter API.
We're excited to announce our biggest update yet for our Kotlin users: KotlinTestParameters.
The de facto standard for parameterized testing
When we first introduced TestParameterInjector, we shared a graph showing its rapid adoption within Google. Over the past few years, that trajectory has continued to a point where TestParameterInjector is the de facto parameterized test framework.
Usage of all other alternative frameworks continues to steadily decline, while TestParameterInjector's adoption keeps growing rapidly. It has fundamentally lowered the barrier to writing data-driven unit tests, empowering Googlers and open source developers alike to maximize test coverage with minimal boilerplate. We believe its ubiquity internally is a strong testament to its reliability and utility for the broader developer communities.
The Kotlin challenge
As Kotlin's popularity has surged, developers have naturally been writing more of their TestParameterInjector tests in Kotlin. However, specifying explicit test values in Kotlin historically meant falling back to Java-centric paradigms.
If you wanted to provide specific values to a test, you typically had three options, none of which felt truly idiomatic in Kotlin:
@TestParameter({"123", "456"}): This relies on string arrays, limiting you to a subset of types that the string parsing supports.@TestParameters: This allows for more complex sets of data, but relies on YAML strings (e.g.,"{age: 17, expectIsAdult: false}"). These strings however are not type-safe, and are completely ignored by IDE refactoring tools.- Provider classes: For complex types that couldn't be easily represented in strings, you have to write
Providerclasses, adding a bit of boilerplate code and indirection.
Enter KotlinTestParameters
To bring a seamless experience to Kotlin, we are introducing a significant new Kotlin-only feature: KotlinTestParameters.
By leveraging Kotlin's default function arguments, you can now define parameterized tests in a fully type-safe, concise, and refactor-friendly way using the testValues() function (and friends).
Here is what it looks like in practice:
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.KotlinTestParameters.testValues
import com.google.testing.junit.testparameterinjector.KotlinTestParameters.namedTestValues
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(TestParameterInjector::class)
class MyTest {
// Testing simple types directly
@Test
fun simpleTest(@TestParameter limit: Int = testValues(20, 100)) {
// This test method is run twice: once for limit=20 and once for limit=100
}
// Testing complex types without YAML strings or Provider classes!
data class TestCase(val age: Int, val expectIsAdult: Boolean)
@Test
fun complexTest(
@TestParameter testCase: TestCase = namedTestValues(
"teenager" to TestCase(age = 17, expectIsAdult = false),
"young adult" to TestCase(age = 22, expectIsAdult = true)
)
) {
// This test method is run twice with fully typed data class instances
}
}
Why we recommend making the switch
Because testValues() seamlessly integrates with Kotlin's language features, any type is supported. This completely eliminates the need for stringly-typed YAML maps or verbose Provider classes.
We firmly believe that KotlinTestParameters is a massive leap forward in readability and maintainability. Moving forward, this should be the default way of specifying test values for all new Kotlin tests, replacing the older @TestParameters, @TestParameter({"..."}), and Provider class patterns.
Try it out!
You can read more and start using KotlinTestParameters today over on our GitHub repository.
Let us know what you think on GitHub if you have any questions, comments, or feature requests!