How to create a parameterized base test class in Kotlin


One exciting feature of JUnit 4 (and 5 as well, but this post will be focused on JUnit 4) is the possibility of running the same test with different input arguments.

That is made possible by a custom test runner called Parameterized, which will inject the provided arguments in the constructor of the test class. Instead, the different arguments must be defined in the companion object of the test class.

@RunWith(Parameterized::class)  
class KotlinVersionTest(val kotlinVersion: String) {  
  
    @Test  
    fun `Kotlin version is correct`() {  
        assertTrue(kotlinVersion.contains("1.7"))  
    }  
  
    companion object {  
        @JvmStatic  
        @Parameterized.Parameters(name = "with kotlinVersion {0}")  
        fun data() = listOf(  
            "1.7.0",  
            "1.7.10",  
            "1.7.20",  
            "1.7.21",  
        )  
    }  
}

However, in some situations, having a base test class helps set up a shared test environment.

open class BaseTest {  
  
    lateinit var kotlinFeatures: KotlinFeatures  
  
    @Before  
    open fun setup() {  
        kotlinFeatures = KotlinFeatures(kotlinVersion = "1.7.0")  
    }  
  
    @After  
    fun cleanUp() {  
       // Cleaning up stuff  
    }   
}
class KotlinVersionParameterizedTest {  
  
    @Test  
    fun `When the Kotlin version is 1_7_0, getNewFeatures returns the correct data`() {  
        val kotlinFeatures = KotlinFeatures(kotlinVersion = "1.7.0")  
  
        assertNotNull(kotlinFeatures)  
    }  
}

But what if KotlinFeatures needs to be tested with multiple kotlinVersion?

The BaseTest can be modified with a constructor that accepts an argument and a companion object that contains all the arguments required for the test.

open class BaseTest(  
    private val kotlinVersion: String,  
) {  
  
    lateinit var kotlinFeatures: KotlinFeatures  
  
    @Before  
    open fun setup() {  
        kotlinFeatures = KotlinFeatures(kotlinVersion = kotlinVersion)  
    }  
  
    @After  
    fun cleanUp() {  
       // Cleaning up stuff  
    }  
  
    companion object {  
        @JvmStatic  
        @Parameterized.Parameters(name = "with kotlinVersion {0}")  
        fun data() = listOf(  
            "1.7.0",  
            "1.7.10",  
        )  
    }  
}

The test classes can now implement the BaseTest and run with the Parameterized test runner. It is only necessary to pass the argument to the Base Class’s constructor.

@RunWith(Parameterized::class)  
class KotlinVersionParameterizedBaseTest(kotlinVersion: String): BaseTest(kotlinVersion) {  
  
    @Test  
    fun `getNewFeatures returns some data`() {  
        val newFeatures = kotlinFeatures.getNewFeatures()  
        assertNotNull(newFeatures)  
    }  
}

And that’s all! This way, running the same tests with different arguments and a shared configuration will be possible.