【问题标题】:@Inject field during test phase@Inject 测试阶段的字段
【发布时间】:2016-07-02 15:00:21
【问题描述】:

我正在向我的应用程序添加日志记录功能,并且我正在使用由log4j 实现的slf4j。为了简化我的代码,我有一个辅助类来生成一个记录器(这个想法不是我的,我是从Beginning Java EE 7 by Antonio Goncalves那里得到的),这个类是这样的:

import javax.enterprise.inject.Produces;
import javax.enterprise.inject.spi.InjectionPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggerProducer {

    @Produces
    public Logger createLogger(InjectionPoint injPoint) {
        return LoggerFactory.getLogger(injPoint.getMember().getDeclaringClass());
    }
}

所以在我的课堂上,我所要做的(理论上)是:

public class SomeClass {
    @Inject private Logger logger; // this could be private or default, doesn't matter
}

问题是在测试阶段我没有启用 CDI,因为我在容器外运行代码。我无法手动注入,因为我有一些带有自己的记录器的抽象类,所以我无法实例化该类并为其分配一个 Logger 实例。

有没有办法在测试阶段“启用”CDI?我的项目是用 Maven 构建的,我将部署到 Wildfly 10 服务器。提前感谢您的回答。

注意

我不能这样做

public class SomeClassTest {
    private SomeClass someClass; // this is the class I want to test

    @Before
    public void init() {
        someClass.logger = LoggerFactory.getLogger(SomeClass.class);
    }

    @Test
    public void someTest(){...}
}

因为我有一些具有自己私有 Logger logger 属性的抽象类,我需要保持这种状态(我不能声明它 protected )因为我想跟踪消息被抛出的位置,所以我需要将记录器保密。例如。我有类似的东西

public abstract class MyAbstract {
    @Inject
    private Logger logger;
}

public class MyConcrete extends MyAbstract {
    @Inject
    private Logger logger;
}

我可以在测试类中将MyConcrete.logger 设置为默认值,但我可以t do that forMyAbstract.loggerbecause they are in different packages and I can't instantiateMyAbstract`,我解释正确吗?

注2

我的项目结构是这样的:

package common

import org.slf4j.logger
...

public abstract class Generic {
    @Inject
    private Logger logger;

    public void doSomethingGeneric(){
        // do something and log it
    }
}

package specific

import ...

public class Concrete extends Generic{
    @Inject
    Logger logger;

    // some concrete methods...
}

package specific

public class ConcreteTest {
    private Concrete concrete;

    @Before
    public void init() {
        concrete = new Concrete();
        concrete.logger = LoggerFactory.getLogger(Concrete.class); // Dependency injection by hand
    }

    // some @Test methods
}

最终,来自ConcreteTest@Test 方法调用Concrete.doSomethingGeneric(),因为它被继承到concrete 实例。问题是doSomethingGeneric() 使用Generic 记录器进行日志记录,我不知道如何以干净的方式满足这种依赖关系(我不希望使用生产中不必要的setter 方法来破解我的代码)

【问题讨论】:

  • arquillian.orgDeltaSpike Test Controljglue.org/cdi-unit 几种方法来做到这一点。
  • “在测试阶段”:你的意思是通过 JUnit 运行单元测试吗?
  • @Heri,没错。我的意思是在 src/test/java 中运行我所有的 @Test 方法时
  • @JohnAment, AFAIK, Arquillian 用于集成测试(在容器内测试);其他两个工件用于编写基于 CDI 的测试。我的情况也不是。我只想在测试阶段获得Logger 的实例
  • 如果你使用 spring 注释 @RunWith(SpringJUnit4ClassRunner.class) 会有所帮助,可能后面跟着注释 @ContextConfiguration(classes={ MyConfigClass1.class, MyConfigClass2.class })。我不知道是否有没有弹簧的替代品。

标签: java maven log4j cdi


【解决方案1】:

你可以这样做,使用 mockito 测试单元:

@RunWith(MockitoJUnitRunner.class)
public class MyBeanTest {

  @Spy
  private Logger logger = LoggerProducer.getLogger();

  @InjectMocks
  private MyBean myTestBean; // = new MyBean(parameters). explicit if no default constructir

  @Test
  public void verifySomeLogic() {
    myTestBean.doSomething();
  }
}

在这里,mockito 运行时和代理将管理注入,您甚至可以对记录器本身进行验证。

【讨论】:

    猜你喜欢
    • 2014-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-22
    • 2017-01-29
    • 2011-02-24
    • 2021-04-05
    • 2019-03-11
    相关资源
    最近更新 更多