Failed
Failed

Reputation: 298

Use pure Kotlin function as Junit5 methodsource

I am curious if in the Kotlin, in the parameterized tests in Junit5, i can use the method outside the class as the @MethodSource.

I know about 2 ways to use @MethodSource in Kotlin - companion object and @TestInstance(TestInstance.Lifecycle.PER_CLASS). I wonder if it can be done in a different way, for example by declaring a method outside the class and using some annotation? I tried to do it this way, but it does not work, I wonder if something similar can be done.

class GenerationStatusTest {

    @ParameterizedTest
    @MethodSource("provideStatusesToTest")
    internal fun shouldStatusesHaveExpectedAbilities(generationStatus: GenerationStatus, assertions:(GenerationStatus)->Unit) {
        assertions(generationStatus)
    }
}

fun provideStatusesToTest(): Stream<Arguments> {
    return Stream.of(
            Arguments.of(WAITING, canDoNothing),
            Arguments.of(PROCESSING, canDoNothing)
    )
}
org.junit.platform.commons.JUnitException: Could not find factory method [provideStatusesToTest] in class [com.test.enums.GenerationStatusTest]
    at org.junit.jupiter.params.provider.MethodArgumentsProvider.lambda$getMethod$4(MethodArgumentsProvider.java:83)

Upvotes: 26

Views: 13514

Answers (3)

AHH
AHH

Reputation: 1083

I followed the answers here to adjust a test in Kotlin, and this is how it worked:

import org.junit.Assert.assertNotNull
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource

class ParametrizedTestTest {

    companion object {
        @JvmStatic fun hashMapProvider() = mapOf(
            "1" to "Obj1",
            "2" to "Obj2"
        ).entries
    }

    @ParameterizedTest
    @MethodSource("hashMapProvider")
    fun testMyMapObj(argument: Map.Entry<String, Any>) {
        assertNotNull(argument)
    }
}

Upvotes: 2

Cafer Mert Ceyhan
Cafer Mert Ceyhan

Reputation: 1756

The best solution is adding @JvmStatic annotation to your provider function.

class SumTest {

    @ParameterizedTest(name = "{0} + {1} = {2}")
    @MethodSource("sumProvider")
    fun sum(a: Int, b: Int, expected: Int) {
        Truth.assertThat((a + b)).isEqualTo(expected)
    }

    companion object {
        @JvmStatic
        fun sumProvider(): Stream<Arguments> {
            return Stream.of(
                    Arguments.of(1, 2, 3),
                    Arguments.of(5, 10, 15)
            )
        }
    }
}

Upvotes: 44

Alexey Romanov
Alexey Romanov

Reputation: 170745

JUnit documentation says

An external, static factory method can be referenced by providing its fully qualified method name as demonstrated in the following example.

And Kotlin documentation says

All the functions and properties declared in a file app.kt inside a package org.example, including extension functions, are compiled into static methods of a Java class named org.example.AppKt.

So if the package name is com.test.enums (from the error message), and your file name is GenerationStatusTest.kt, then the generated class containing provideStatusesToTest is com.test.GenerationStatusTestKt, so the annotation you need is

@MethodSource("com.test.enums.GenerationStatusTestKt#provideStatusesToTest")

Upvotes: 19

Related Questions