我们使用testng作为测试框架。我们还使用Lombok @ Log4j2实例化我们的日志对象。我需要测试一些代码,以便在某些情况下记录某些消息。
我已经看到了使用junit和Mockito的示例。但是我无法在testng中找到方法。不能切换到junit。
我已经实现了扩展AbstractLogger的类(CaptureLogger)
import org.apache.logging.log4j.spi.AbstractLogger;
public class CaptureLogger extends AbstractLogger {
...
}
我无法将其连接到被测类的记录器。
CaptureLogger customLogger = (CaptureLogger) LogManager.getLogger(MyClassUnderTest.class);
生成错误消息:
java.lang.ClassCastException: org.apache.logging.log4j.core.Logger cannot be cast to CaptureLogger
我发现LogManager.getLogger返回Logger接口,而不是Logger对象(实现Logger接口)。
如何创建CaptureLogger的实例?
答案 0 :(得分:1)
只要您使用Lombok生成记录器,就不能使用给定工具在源代码本身的水平上做很多事情。例如,如果放置@Log4j2
注释,它将生成:
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
此行已随附编译的代码。
您可以尝试使用PowerMockito模拟LogManager.getLogger方法,但是我真的不喜欢这种工具。请说明这一点,因为它可能是一个可行的方向。
有几种使用框架本身的方法。
一种方法(我不特别喜欢Log4j2,但是它应该提供此功能-多年前我对Log4j 1.x做过类似的事情)是提供您自己的logger实现并将其与logger工厂关联在Log4j2配置级别。 现在,如果您执行此操作,则由lombok生成的代码将返回您的logger实例,该实例可以存储在不同级别记录的消息(这是您必须在Logger级别实现的自定义逻辑)。
然后,记录器将具有方法public List<String> getResults()
,您将在验证阶段调用以下代码:
public void test() {
UnderTest objectUnderTest = ...
//test test test
// verification
MyCustomLogger logger = (MyCutomLogger)LogManager.getLogger(UnderTest.class);
List<String> results = logger.getResults();
assertThat(results, contains("My Log Message with Params I expect or whatever");
}
我可以想到的另一种相似的方式是创建一个自定义附加程序,该附加程序将存储测试期间发送的所有消息。然后,您可以(通过声明或编程方式将该附加程序绑定到LogFactory.getLogger
所获得的Logger中,用于测试的类(或其他类,具体取决于您的实际需求)。
然后让测试工作并进行验证-从log4j2系统获取对附加程序的引用,并使用某种public List<String> getResults()
方法索取结果,除了附加方法外,附加程序上还必须存在什么内容必须遵守才能遵守Appender合同。
所以测试可能看起来像这样:
public void test () {
MyTestAppender app = createMemorizingAppender();
associateAppenderWithLoggerUnderTest(app, UnderTest.class);
UnderTest underTest = ...
// do your tests that involve logging operations
// now the verification phase:
List<String> results = app.getResults();
assertThat(results, contains("My Log Message with Params I expect or whatever");
}
答案 1 :(得分:1)
你可以像这样定义你自己的 appender:
package com.xyz;
import static java.util.Collections.synchronizedList;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
@Plugin(name = "LogsToListAppender", category = "Core", elementType = Appender.ELEMENT_TYPE)
public class LogsToListAppender extends AbstractAppender {
private static final List<LogEvent> events = synchronizedList(new ArrayList<>());
protected LogsToListAppender(String name, Filter filter) {
super(name, filter, null);
}
@PluginFactory
public static LogsToListAppender createAppender(@PluginAttribute("name") String name,
@PluginElement("Filter") Filter filter) {
return new LogsToListAppender(name, filter);
}
@Override
public void append(LogEvent event) {
events.add(event);
}
public static List<LogEvent> getEvents() {
return events;
}
}
然后在将引用 appender 的类路径的根目录中创建一个名为 log4j2-logstolist.xml
的文件:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="com.xyz" >
<Appenders>
<LogsToListAppender name="LogsToListAppender" />
</Appenders>
<Loggers>
<Root level="TRACE">
<AppenderRef ref="LogsToListAppender" />
</Root>
</Loggers>
</Configuration>
您应该特别注意(正确更新)属性 packages="com.xyz"
(您的 appender 的包),否则它将不可用。有关详细信息,请查看 https://www.baeldung.com/log4j2-custom-appender
最后创建TestNG测试:
package com.xyz;
import static org.testng.Assert.assertTrue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.config.Configurator;
import org.testng.annotations.Test;
@Test
public class LogsTest {
static {
Configurator.initialize(null, "classpath:log4j2-logstolist.xml");
}
@Test
public void testLogs() {
// call your code that produces log, e.g.
LogManager.getLogger(LogsTest.class).trace("Hello");
assertTrue(LogsToListAppender.getEvents().size() > 0);
}
}
如您所见,我们正在强制 Log4j2 在类初始化时使用带有 Configurator.initialize(null, "classpath:log4j2-logstolist.xml");
的自定义配置(static{}
块)。
请记住,检查记录器名称对您也很有用,例如LogsToListAppender.getEvents().stream().filter(a -> CLASS_THAT_PRODUCES_LOG.class.getName().equals(a.getLoggerName())).collect(toList());
您可以使用 LogEvent::getMessage()
方法访问实际消息