weld/weld-testing

@Produces leads to circular dependency

Nerdy-5 opened this issue · 2 comments

Hi folks

I am currently migrating from CDI-Unit to weld-testing 2.0.2. Everything should work pretty much the same, but I have hit a snag:

Tests that use mocks:

	@EnableAutoWeld
	class SomeTest {

	@Inject
	private ABean beanThatUsesUtil;

	@Produces
	@ExcludeBean
	@Mock
	private Util mockedUtil;

	@Test
	....

Result:

WELD-001443: Pseudo scoped bean has circular dependencies. Dependency path:
...
Producer Field [Util] with qualifiers [@Any @default] declared as [[UnbackedAnnotatedField] @produces @ExcludeBean @mock private SomeTest.mockedUtil]

What am I missing? What can I try? These tests where working in a weld container and the code deploys fine on JBoss. Is it worth trying to get weld-junit5 4.x working with Java11 (javax instead of jakarta) or will it just fail as well?

Thanks in advance

Hello @Nerdy-5, below are some explanations.
Let me know if it helps you.

What am I missing? What can I try? These tests where working in a weld container and the code deploys fine on JBoss.

I am pretty sure your previous setup must been slightly different to avoid cyclic dependency as your issue is not with weld-testing but with how CDI itself works (last paragraph in 2.4).
The problem here is that CDI needs to instantiate a bean and inject into all of its fields in order to be able to invoke its producers. So when you ask for Util bean, CDI knows there is a producer inside SomeTest. However, to instantiate SomeTest, it needs Util for one of its injection points - hence the cycle.

Here are some things that you can try. Mind that I don't know your whole scenario so not all might be viable:

  • Turn Util bean into normal scoped bean (bean using a proxy).
    • For instance by putting @ApplicationScope on the producer.
  • Make the producer static
    • CDI won't need to create an instance of the bean to invoke the producer.
  • Move the producer method into another bean
    • In this case I am not sure if we process/pick it up but I think we should so long as it's a bean you use in the test
  • Avoid injecting Util into a field - instead use it as method parameter in whichever test method you need it.
    • This helps because method injection points are only satisfied upon method invocation so CDI can create the bean itself without any cyclic dependency.

Is it worth trying to get weld-junit5 4.x working with Java11 (javax instead of jakarta) or will it just fail as well?

You should use version of weld-testing that's made for given Weld version (and therefore CDI version or Jakarta EE version if you wish) you are running on.
So Weld 5 = weld-testing 4.x (this is where change to jakarta namespace happened).
Weld 4 = weld-testing 3.x (javax namespace).
Functionally, they should be the same except minor bug fixes.

Success!

I think the difference to CDI-Unit is, that Weld-Testing makes @singletons out of the test classes. Making the producer static was simple and effective:

@Produces
@ExcludeBean
@Mock
private static Util mockedUtil;

Thank you also for clarifying which version to use. Didn't catch that before and chose the right one by chance (2.x for weld 3.x)