【问题标题】:Unit test : Produce mock for the unit under test in a parent test class单元测试:在父测试类中为被测单元生成模拟
【发布时间】:2023-03-10 00:01:01
【问题描述】:

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

我有一个使用 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 中制作 Mock 的原因。

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中声明mock时,测试就ok了。但是如果我在 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)

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

即使我不完全同意这篇文章(我可能错了,好吧),它也没有解释为什么我们在超类中创建模拟时会出现模棱两可的依赖问题。

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

非常感谢您的帮助!

【问题讨论】:

    标签: java unit-testing dependency-injection cdi


    【解决方案1】:

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

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

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

    我不得不在 getter 上使用 @Produces:

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

    很遗憾,我无法使用来自 Mockito 和 field-producer 的 @Mock 注释。

    【讨论】:

      猜你喜欢
      • 2019-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-14
      • 1970-01-01
      • 2016-05-09
      • 2013-02-22
      • 2011-04-11
      相关资源
      最近更新 更多