Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@QuarkusComponentTest doesn't initialize injected beans #42643

Closed
dasha-klim opened this issue Aug 20, 2024 · 10 comments
Closed

@QuarkusComponentTest doesn't initialize injected beans #42643

dasha-klim opened this issue Aug 20, 2024 · 10 comments
Labels
area/testing kind/bug Something isn't working

Comments

@dasha-klim
Copy link

dasha-klim commented Aug 20, 2024

Describe the bug

@QuarkusComponentTest doesn't allow to inject a list of classes that implement a specific interface using @Inject @All annotations
Like:

    @Inject
    @All
    List<Secondary> secondaries;

Each class that implements the interface is annotated with @ApplicationScoped
@Startup and has a @Postconstruct method which doesn't get called at all when running a test.

Expected behavior

Classes are injected

Actual behavior

List of classes remains empty.

How to Reproduce?

Reproducer: https://github.com/dasha-klim/quarkus_test.git

Output of uname -a or ver

No response

Output of java -version

17.0.11

Quarkus version or git rev

No response

Build tool (ie. output of mvnw --version or gradlew --version)

gradle

Additional information

If it is expected behaviour and the @QuarkusComponentTest shouldn't allow this to be done, how it should be done without using @QuarkusTest annotation and starting the whole quarkus application as we have a lot of other verticles and services that we don't need for testing.

@dasha-klim dasha-klim added the kind/bug Something isn't working label Aug 20, 2024
@geoand
Copy link
Contributor

geoand commented Aug 21, 2024

cc @mkouba

@mkouba
Copy link
Contributor

mkouba commented Aug 26, 2024

Yes, it seems that we incorrectly detect the component classes for @Inject @All List<>. You can specify additional component classes via @QuarkusComponentTest#value() as a workaround.

@dasha-klim
Copy link
Author

@mkouba Thank you for your reply!
I tried @QuarkusComponentTest(value = SecondaryOne.class) and i tried @QuarkusComponentTest(value = Secondary.class) and i still didn't see sysout from postConstruct method. How should i do this? Also if i specify them one by one in value, how do i call their methods from tests?
Also we have about 30 implementations of the service and its a changing number, it would be complicated to add/remove class in tests when we add/remove a new implementation.
Any chance this will be fixed any time soon?

@mkouba
Copy link
Contributor

mkouba commented Aug 26, 2024

I tried @QuarkusComponentTest(value = SecondaryOne.class) and i tried @QuarkusComponentTest(value = Secondary.class) and i still didn't see sysout from postConstruct method. How should i do this?

You should only add implementations, i.e. something like @QuarkusComponentTest({SecondaryOne.class,SecondaryTwo.class}). But you're right that in your case it's not enough because ArC considers those beans unused and removes them from the configuration automatically :-(.

Unfortunately, the only workaround I can see is to annotate those beans with @Unremovable or simply inject them in the test class.

Also we have about 30 implementations of the service and its a changing number, it would be complicated to add/remove class in tests when we add/remove a new implementation.

I agree that it's not very convenient (although mentioned in the javadoc of @QuarkusComponentTest#value() and in the docs). I'm working on a fix so that @Inject @All List<X> and @Inject Instance<X> are treated in a similar way as @Inject X. But keep in mind that the goal of QuarkusComponentTest is to test a specific set of beans. So it's always good to define the set of components under the test explicitly.

@mkouba
Copy link
Contributor

mkouba commented Aug 26, 2024

@dasha-klim Hm, I've just realized that even if we treat @Inject @All List<X> as @Inject X it would not help in your use case with an interface implemented by several beans. We would be able to exclude the unused beans from removal but we wouldn't be able to register them as additional components. In other words, you would still need to register them with @QuarkusComponentTest#value().

mkouba added a commit to mkouba/quarkus that referenced this issue Aug 27, 2024
- handle programmatic lookup injection points specifically: register
type arguments as tested components and consider these types in the
unused beans removal exclusion
- support programmatic lookup in test method params (`Instance<>`, `@All
List<>`)
- add "Tested components" section in the docs
- related to quarkusio#42643
@dasha-klim
Copy link
Author

@mkouba , thank you for looking into the issue!
I adjusted the code - added @Unremovable to the Secondary implementations and @postconstuct method now puts these implementations in a map created in MainService. I have a getSecondariesMap() method in MainService that returns this map.
In test class in @beforeAll i am trying to get the map using the mentioned method however it seems that Secondary beans are getting initialized and added to map only after i loop through secondaries in test class . When after looping i try to get the map from the MainService again - the map is filled. You can see this according to logs.
I was under impression that adding @Unremovable would initialize the beans right away, even @beforeAll in tests. Could let me now if it is expected behaviour? Thank you.

@dasha-klim
Copy link
Author

@mkouba
Its not in the project that i linked for reproduction, but in our project the services (that are like Secondaries) also use Vertx.
If i try to inject Vertx using @Inject Vertx vertx i get java.lang.IllegalStateException: The injected field io.vertx.core.Vertx TestClassName.vertx expects a real component; but obtained: SYNTHETIC bean.
If i don't inject Vertx in test class, i get NullPointerException from bean Cannot invoke "io.vertx.core.eventbus.EventBus.request(String, Object, io.vertx.core.Handler)" because the return value of "io.vertx.core.Vertx.eventBus()" is null
How can i make sure that when using @QuarkusComponentTest the beans specified via @QuarkusComponentTest#value() would be able to use Vertx? Can i inject it via TestClass or should it be done some other way?
Thank you.

@mkouba
Copy link
Contributor

mkouba commented Aug 27, 2024

I was under impression that adding @Unremovable would initialize the beans right away, even @beforeAll in tests. Could let me now if it is expected behaviour? Thank you.

Not really. @Unremovable merely prevents the beans from being removed (if considered unused).

Unfortunately, you can't use @QuarkusComponentTest + @BeforeAll to initialize the tested components. You can however use the QuarkusComponentTestExtension.builder() as mentioned in the basic example.

@mkouba
Copy link
Contributor

mkouba commented Aug 27, 2024

If i try to inject Vertx using @Inject Vertx vertx i get java.lang.IllegalStateException: The injected field io.vertx.core.Vertx TestClassName.vertx expects a real component; but obtained: SYNTHETIC bean.

I assume you're trying to inject Vertx in the test? If so then you'll have to (a) provide your own Vertx implementation and add it to the set of tested components, or (b) use @InjectMock and configure the mock instead.

mkouba added a commit to mkouba/quarkus that referenced this issue Aug 28, 2024
- handle programmatic lookup injection points specifically: register
type arguments as tested components and consider these types in the
unused beans removal exclusion
- support programmatic lookup in test method params (`Instance<>`, `@All
List<>`)
- add "Tested components" section in the docs
- related to quarkusio#42643
gsmet pushed a commit to gsmet/quarkus that referenced this issue Sep 2, 2024
- handle programmatic lookup injection points specifically: register
type arguments as tested components and consider these types in the
unused beans removal exclusion
- support programmatic lookup in test method params (`Instance<>`, `@All
List<>`)
- add "Tested components" section in the docs
- related to quarkusio#42643

(cherry picked from commit 04a0211)
@mkouba
Copy link
Contributor

mkouba commented Sep 16, 2024

As explained in #42643 (comment) we can't fix this issue completely. The fix in #42779 is IMO the best thing we can do. Feel free to reopen this issue or open a new discussion.

@mkouba mkouba closed this as completed Sep 16, 2024
danielsoro pushed a commit to danielsoro/quarkus that referenced this issue Sep 20, 2024
- handle programmatic lookup injection points specifically: register
type arguments as tested components and consider these types in the
unused beans removal exclusion
- support programmatic lookup in test method params (`Instance<>`, `@All
List<>`)
- add "Tested components" section in the docs
- related to quarkusio#42643
bschuhmann pushed a commit to bschuhmann/quarkus that referenced this issue Nov 16, 2024
- handle programmatic lookup injection points specifically: register
type arguments as tested components and consider these types in the
unused beans removal exclusion
- support programmatic lookup in test method params (`Instance<>`, `@All
List<>`)
- add "Tested components" section in the docs
- related to quarkusio#42643
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/testing kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants