micronaut-projects / micronaut-test

Repository for Test Related Utilities for Micronaut
Apache License 2.0
81 stars 60 forks source link

Multiple competing ParameterResolvers error after upgrading to Micronaut 3.7 #661

Closed danielmatthews84 closed 1 year ago

danielmatthews84 commented 1 year ago

Expected Behavior

Unit tests using JUnit5 @ParameterizedTest are no longer working since upgrading to Micronaut 3.7.

The following test should run without error:

@Data
public class Foo {
    @Bar
    private Object value;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
public @interface Bar {
}
@MicronautTest
class FooTest {

    static Stream<Arguments> fooArgs() {
        return Stream.of(Arguments.of(new Foo()));
    }

    @ParameterizedTest
    @MethodSource("fooArgs")
    void foo(Foo arg) {
    }
}

This was working correctly with Micronaut 3.6

Actual Behaviour

Exception when running test:

Discovered multiple competing ParameterResolvers for parameter [com.example.Foo arg] in method [void com.example.FooTest.foo(com.example.Foo)]: io.micronaut.test.extensions.junit5.MicronautJunit5Extension@5d235104, org.junit.jupiter.params.ParameterizedTestParameterResolver@4e8e8621

The combination of using both Lombok's @Data and the custom @Constraint annotation appears to create a bean definition reference synthetic class $Foo$Definition$Reference which in turn makes the Foo class eligible as a Micronaut managed bean and therefore is being picked up by the MicronautJunit5Extension

Removing either annotation prevents the synthetic class from being generated and fixes the test.

Steps To Reproduce

Environment Information

Example Application

No response

Version

3.7

lucjross-favor commented 1 year ago

I'm experiencing the same but with a Parameterized Argument of type kotlin.jvm.functions.Function1 (any lambda). Similar to this issue, Micronaut Test is being too greedy about parameter types.

graemerocher commented 1 year ago

Attach an example please

lucjross-favor commented 1 year ago

Hi Graeme, of course. In Kotlin:

fun tokenTypeExpectations() = listOf<Arguments>(
        Arguments.of(TokenType.GCM, { token: String -> AddRegistrationOrDeviceTokenData().gcmRegToken(token) }),
        Arguments.of(TokenType.APNS, { token: String -> AddRegistrationOrDeviceTokenData().apnsDeviceToken(token) }),
        Arguments.of(TokenType.HUAWEI, { token: String -> AddRegistrationOrDeviceTokenData().huaweiDeviceToken(token) }),
    )

    @ParameterizedTest
    @MethodSource("tokenTypeExpectations")
    fun `works`(
        tokenType: TokenType, (token: String) -> AddRegistrationOrDeviceTokenData
    ) { ...

Error:

Discovered multiple competing ParameterResolvers for parameter [kotlin.jvm.functions.Function1<? super java.lang.String, ? extends ....AddRegistrationOrDeviceTokenData> reqBody] in method [public final void ....PushRegistrationEventHandlerIT.works(....PushRegistrationEventData$TokenType,kotlin.jvm.functions.Function1<? super java.lang.String, ? extends ....AddRegistrationOrDeviceTokenData>)]: io.micronaut.test.extensions.junit5.MicronautJunit5Extension@635d036b, org.junit.jupiter.params.ParameterizedTestParameterResolver@35965cb6

Dependencies:

graemerocher commented 1 year ago

added a PR to disable bean resolution for methods which is the only viable solution to this issue https://github.com/micronaut-projects/micronaut-test/pull/727