1

Consider the following Quarkus application:

@ApplicationScoped
@Path("/hello")
public class HelloService {

    @Inject
    Helper helper;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHello(){
        return "Hello "+helper.getName();
    }
}


@Dependent
public class Helper {

    public String getName() {
        return "World";
    }
}

and the following Test:

@QuarkusTest
@TestHTTPEndpoint(HelloService.class)
public class HelloQuarkusTest {

    @Test
    void testSayHello(){
        given().when().then().body(is("Hello World"));
    }
}

Everything's fine up to this point. The service and its helper are of course a bit more complicated than that in reality. So I want to have some unit tests. If I write a unit test for the service like so:

@EnableAutoWeld
@ExtendWith(MockitoExtension.class)
class HelloUnitTest {

    @Inject
    HelloService helloService;

    @Produces @Mock
    @ExcludeBean // don't use the real bean, use this instead
    Helper helperMock;

    @Test
    void testSayHello(){
        when(helperMock.getName()).thenReturn("Mock");
        final String actual = helloService.sayHello();
        assertThat(actual).isEqualTo("Hello Mock");
    }
}

Then the unit test is green, but suddenly the @QuarkusTest fails, because it finds both the real Helper implementation and the producer field from the unit test and consequently throws an AmbiguousResolutionException:

java.lang.RuntimeException: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
    [error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.AmbiguousResolutionException: Ambiguous dependencies for type com.example.Helper and qualifiers [@Default]
    - java member: com.example.HelloService#helper
    - declared on CLASS bean [types=[com.example.HelloService, java.lang.Object], qualifiers=[@Default, @Any], target=com.example.HelloService]
    - available beans:
        - CLASS bean [types=[java.lang.Object, com.example.Helper], qualifiers=[@Default, @Any], target=com.example.Helper]
        - PRODUCER FIELD bean [types=[java.lang.Object, com.example.Helper], qualifiers=[@Default, @Any], target=com.example.Helper com.example.weld.HelloUnitTest.helperMock, declaringBean=com.example.weld.HelloUnitTest]

This happens even if the tests are in different packages. To some extend I understand why scanning more than one class/package is intended for a @QuarkusTest, but I don't like it in this case.

So my question is:

How can I configure what beans/classes/packages a @QuarkusTest picks up and which it ignores?

I have tried playing around with the Arc settings in application-test.properties, but so far have not found the right combination of properties.

Johannes Hahn
  • 363
  • 3
  • 18
  • This is bad, it seems that Quarkus tests and weld-junit do not play well together. It would be better if there was a rule to exclude any bean definitions from test classes that are not the current test, but that too may not be possible due to how Quarkus tests work (if my understanding is correct). In simple projects I have gotten away with it by splitting the code into Maven modules, and running weld-junit tests on the business logic and Quarkus tests only on the main assembly project. What happens if you make the `@Produces @Mock` field private, as a workaround? – Nikos Paraskevopoulos Apr 04 '22 at 11:55
  • 1
    I agree, it's non-trivial, because @QuarkusTest is not as isolated as a unit test and as far as I understand it, this is intended. So @QuarkusTest needs to scan many other classes, no question. Making the producer field private does not help, it still gets found. However, it's not as bad as it seems, because Weld-JUnit can also be configured programmatically with a `@WeldSetup WeldInitiator` field instead so that no producer field or method is strictly necessary. Unsurprisingly, this quickly gets annoyingly verbose and I was hoping for a "don't look over there" configuration. – Johannes Hahn Apr 04 '22 at 15:19

1 Answers1

1

You could try to add all the weld-junit unit tests in a specific package and exclude this package from quarkus discovery via quarkus.arc.exclude-types; i.e. something like %test.quarkus.arc.exclude-types=org.acme.unit.tests.**.

Martin Kouba
  • 1,121
  • 5
  • 8