I'm currently working with CDI Unit on a project, and i've encountered a strange problem. I tried to reproduce it in a simple project :
I've a test class that i run with CdiRunner (as explained right here : http://jglue.org/cdi-unit-user-guide/ My Test class inject the unit under test : UUD. This class extends a super class "ParentTestClass" that is currently useless.
TestClass.java :
package fr.perso.tutorial.cdiunit.test;
import javax.inject.Inject;
import org.jglue.cdiunit.CdiRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
import fr.perso.tutorial.cdiunit.controller.UUD;
@RunWith(CdiRunner.class)
public class TestClass extends ParentTestClass {
@Inject
private UUD uud;
@Produces
@Mock
private MyController myController;
@Test
public void test() {
}
}
As i mentionned, the parent class is empty.
ParentTestClass.java :
package fr.perso.tutorial.cdiunit.test;
public class ParentTestClass {
}
As we can see, the unit under test need MyController to work. That's why I produced a Mock in my TestClass.
UUD.java :
package fr.perso.tutorial.cdiunit.controller;
import javax.inject.Inject;
import org.junit.Before;
public class UUD {
@Inject
private MyController myController;
@Before
private void initialize(){
System.out.println("I'm the unit under test and i need this controller to work : " + myController.toString());
}
}
MyController .java :
package fr.perso.tutorial.cdiunit.controller;
public class MyController {
@Override
public String toString() {
return "[controller : " + super.toString() + "]";
}
}
Okay here is the problem : when we declare the mock in TestClass, the test is ok. But if i declare it in the ParentTestClass, we have the following error :
org.jboss.weld.exceptions.DeploymentException: WELD-001409: Ambiguous dependencies for type MyController with qualifiers @Default
at injection point [BackedAnnotatedField] @Inject private fr.perso.tutorial.cdiunit.controller.UUD.myController
at fr.perso.tutorial.cdiunit.controller.UUD.myController(UUD.java:0)
Possible dependencies:
- Producer Field [MyController] with qualifiers [@Any @Default] declared as [[UnbackedAnnotatedField] @Produces @Mock private fr.perso.tutorial.cdiunit.test.TestClass.myController],
- Managed Bean [class fr.perso.tutorial.cdiunit.controller.MyController] with qualifiers [@Any @Default],
- Producer Field [MyController] with qualifiers [@Any @Default] declared as [[BackedAnnotatedField] @Produces @Mock private fr.perso.tutorial.cdiunit.test.ParentTestClass.myController]
at org.jboss.weld.bootstrap.Validator.validateInjectionPointForDeploymentProblems(Validator.java:367)
at org.jboss.weld.bootstrap.Validator.validateInjectionPoint(Validator.java:281)
at org.jboss.weld.bootstrap.Validator.validateGeneralBean(Validator.java:134)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:155)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:518)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:68)
at org.jboss.weld.bootstrap.ConcurrentValidator$1.doWork(ConcurrentValidator.java:66)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:60)
at org.jboss.weld.executor.IterativeWorkerTaskFactory$1.call(IterativeWorkerTaskFactory.java:53)
at java.util.concurrent.FutureTask.run(FutureTask.java:262)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
I would have liked create the mock in a superclass for duplicate code purpose in my project. I know that some people consider using super test class is a code smell (here for example : https://www.petrikainulainen.net/programming/unit-testing/3-reasons-why-we-should-not-use-inheritance-in-our-tests/)
Even if i'm not fully agree with this article (and i may be wrong okay), it does not explain why there is an ambigous dependencies problem when we create the mock in the superclass.
Anyone know why there is this problem and know how to solve it except by writing all the code in a single class?
Thank you very much for your help!