【发布时间】:2018-07-09 12:25:24
【问题描述】:
我正在使用com.portingle:slf4jtesting:1.1.3 来帮助测试一些日志记录功能。
我的问题是com.portingle 的开发人员是strong advocates of dependency injection,并建议仅使用他们的slf4jtesting::ILoggerFactory 实用程序进行依赖注入(slf4j 的实现,它存储日志条目以便于测试和验证)。
通过依赖注入,我可以像这样在我的类中创建我的 slf4j 记录器并注入生产或测试LoggerFactory:
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
public class Example1 {
private final Logger logger;
public Example1(ILoggerFactory lf) {
this.logger = lf.getLogger(Example1.class.getName());
}
public void aMethodThatLogs() {
logger.info("Hello World!");
}
}
足够合理,但我有一个遗留应用程序,并且我所有的记录器都已经编码并且有时在静态代码块/方法中使用,因此标准 DI 构造函数注入将不起作用。
目前我正在这样做:
private static final Logger log = LoggingUtils.getLogger(
RequestLoggingFilter.class);
而LoggingUtils 看起来像这样:
public class LoggingUtils {
private LoggingUtils() {
}
private static ILoggerFactory iLoggerFactory =
LoggerFactory.getILoggerFactory();
/**
* We don't want to call this in production.
*/
public static void switchToTestLogging() {
iLoggerFactory = Settings.instance().enableAll().buildLogging();
}
/**
* Return logger for a class, of whatever implementation is running,
* e.g. test or prod logger.
*
* @param loggingClass the class doing the logging
* @return logger
*/
public static Logger getLogger(Class loggingClass) {
return iLoggerFactory.getLogger(loggingClass.getName());
}
所以在测试中,我可以通过调用我的switchToTestLogging() 切换到slf4jtesting::ILoggerFactory,但最终结果是我的生产代码中有slf4jtesting 代码。
或者,我可以将 iLoggerFactory 公开,以便测试可以在必要时替换它,但允许任何生产代码这样做是不好的做法。
最后,我可以在我的LoggingUtils 班级中use reflection to hack the private ILoggerFactory instance 并在测试期间分配一个测试LoggerFactory:
@BeforeAll
public static void setupLogging()
throws NoSuchFieldException, IllegalAccessException {
Field loggerFactoryField =
LoggingUtils.class.getDeclaredField("iLoggerFactory");
loggerFactoryField.setAccessible(true);
loggerFactoryField.set(null,
Settings.instance().enableAll().buildLogging());
}
但这也不完全是“最佳实践”。
有什么方法可以让ILoggerFactory 实例保持私有,避免反射并让测试库停止生产?
【问题讨论】:
-
虽然不是静态耦合的忠实拥护者,但您可以完全删除
switchToTestLogging并在测试模拟工厂方法以在调用时返回所需的记录器。 PowerMockito 应该可以让你模拟静态成员。
标签: java unit-testing dependency-injection slf4j