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

WeldInitiator does not call @PostConstruct methods #229

Closed
jetztgradnet opened this issue Jan 16, 2025 · 4 comments
Closed

WeldInitiator does not call @PostConstruct methods #229

jetztgradnet opened this issue Jan 16, 2025 · 4 comments

Comments

@jetztgradnet
Copy link

jetztgradnet commented Jan 16, 2025

When injecting targets (beans, test classes, ...) in JUnit5 tests with WeldJunit5Extension, methods annotated with @jakarta.annotation.PostConstruct are not executed, which does not fulfil the contract described by Weld (see https://docs.jboss.org/weld/reference/5.1.4.Final/en-US/html_single/#_injecting_java_ee_resources_into_a_bean).

Essentially, AbstractWeldInitiator.ToInject#inject() is missing a call to injectionTarget.postConstruct(instance); after performing the injection.

See https://github.com/weld/weld-testing/blob/master/junit-common/src/main/java/org/jboss/weld/junit/AbstractWeldInitiator.java#L328 for the respective code.

Example with pseudo code:

@ExtendWith(WeldJunit5Extension.class)
public class MyTest {

    @Inject
    protected SomeDependency someDep;

    // create Weld with auto discovery enabled and additional scope RequestScoped
    @WeldSetup
    protected WeldInitiator weld = WeldInitiator.from(new Weld()).activate(RequestScoped.class).build();

    @PostConstruct
    protected void postConstruct() {
        someDep.doSomething();
    }

    @Test
    public void testSomething() throws Exception {
        // test something which requires that the post construct above was executed.
    }

}

For now I use @Inject instead of @PostConstruct as a workaround, but that only works, because all my other injections are for fields which are guaranteed to be set before calling methods.

I used Weld 5.1.4.Final and weld-testing 4.0.3.Final.

@manovotn
Copy link
Collaborator

Hello and thanks for the report @jetztgradnet.

Why do you need to perform post construct on the test object?
If you need a pre-test initialization/logic, I'd say that Junit lifecycle callback (such as @BeforeEach or @BeforeAll) are a better fit?

When injecting targets (beans, test classes, ...) in JUnit5 tests with WeldJunit5Extension, methods annotated with @jakarta.annotation.PostConstruct are not executed, which does not fulfil the contract described by Weld (see https://docs.jboss.org/weld/reference/5.1.4.Final/en-US/html_single/#_injecting_java_ee_resources_into_a_bean).

Note that the test instance is not a managed bean and as such does not follow this contract. It is in fact provided by JUnit (which also controls its lifecycle) and we just inject into it for convenience.
We could also trigger post construct callback but it's a bit iffy since it is not really happening right after object construction and its primary use is already met by JUnit callbacks anyway.

@jetztgradnet
Copy link
Author

Thanks for the quick response!
Ok, that makes sense. IIRC, I used @PostConstruct for this because I was not sure whether the order of execution of @ExtendWith compared to @BeforeEach was guaranteed. But if you say that I can rely on this order, then yes, we do not need support for @PostConstruct here.
Should I then rather close this issue or would you add this invocation anyway for completeness?

@manovotn
Copy link
Collaborator

Ok, that makes sense. IIRC, I used @PostConstruct for this because I was not sure whether the order of execution of @ExtendWith compared to @beforeeach was guaranteed.

This should be guaranteed by the JUnit specification. Extensions (@ExtendWith) intercept and enrich the lifecycle at various points but do not cancel it out.
Here's an example of a BeforeEachCallback that you can hook into that takes place right before @BeforeEach is invoked.

Should I then rather close this issue or would you add this invocation anyway for completeness?

I will close it; given current setup, invoking @PostConstruct doesn't feel right.

FTR, the reason why JUnit provides the instance and not Weld is mostly historical as in early days of JUnit this wasn't possible and later on it was a breaking change to rewrite it.
That being said, there are now two other issues (#144, #156) that suggest we should consider doing that.
If we end up rewriting that, it would automatically solve this issue as well because, as you correctly pointed out, any managed bean will have post construct callback invoked.

@jetztgradnet
Copy link
Author

Thanks for your time and helping me with the explanation! Greatly appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants