单元测试:在父测试类中为被测单元生成模拟

时间:2016-09-12 14:21:12

标签: java unit-testing dependency-injection cdi

我目前正在与CDI部门合作开展一个项目,但我遇到了一个奇怪的问题。我试图在一个简单的项目中重现它:

我使用CdiRunner运行的测试类(如右图所示:http://jglue.org/cdi-unit-user-guide/ 我的测试类注入被测单元:UUD。这个类扩展了一个超类" ParentTestClass"这是目前无用的。

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() {

    }
}

正如我所提到的,父类是空的。

ParentTestClass.java:

package fr.perso.tutorial.cdiunit.test;


public class ParentTestClass {

}

正如我们所看到的,被测单元需要MyController才能工作。这就是我在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() + "]";
    }
}

好的问题是:当我们在TestClass中声明模拟时,测试是可以的。但是如果我在ParentTestClass中声明它,我们会出现以下错误:

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)

我希望在我的项目中为超类代码创建一个超类中的mock。我知道有些人认为使用超级测试类是代码气味(例如:https://www.petrikainulainen.net/programming/unit-testing/3-reasons-why-we-should-not-use-inheritance-in-our-tests/

即使我不完全同意这篇文章(我可能错了),但它并没有解释为什么我们在超类中创建模拟时存在一个不明确的依赖问题。

任何人都知道为什么会出现这个问题并知道如何解决它,除非通过在一个类中编写所有代码?

非常感谢你的帮助!

1 个答案:

答案 0 :(得分:0)

我偶然发现了同样的事情。 答案在这里:https://stackoverflow.com/a/32985745/6324171

当您尝试在抽象类或父类中生成时,它不起作用,因为@Produces不会被继承。

我将我的模拟生产者转换到了另一个类(如在建议的其他答案中),并且它按预期工作。

我不得不在吸气剂上使用@Produces:

public class DateAndTimeMasterForTestProducer {

    @Produces
    @ApplicationScoped
    public DateAndTimeMaster getDateAndTimeMaster() {
        return mock(DateAndTimeMasterImpl.class);
    }

}

我很遗憾无法使用Mockito和现场制作人的@Mock注释。