Unit testing 如何使用testng对日志消息进行单元测试
我们使用testng作为输出测试框架。我们还使用Lombok@Log4j2来实例化日志对象。我需要测试一些代码,它在特定条件下记录特定消息 我见过使用junit和Mockito的示例。但是我找不到如何在testng中实现它。切换到junit不是一个选项 编辑 我实现了一个类(CaptureLogger),它扩展了AbstractLoggerUnit testing 如何使用testng对日志消息进行单元测试,unit-testing,testng,log4j2,lombok,Unit Testing,Testng,Log4j2,Lombok,我们使用testng作为输出测试框架。我们还使用Lombok@Log4j2来实例化日志对象。我需要测试一些代码,它在特定条件下记录特定消息 我见过使用junit和Mockito的示例。但是我找不到如何在testng中实现它。切换到junit不是一个选项 编辑 我实现了一个类(CaptureLogger),它扩展了AbstractLogger import org.apache.logging.log4j.spi.AbstractLogger; public class CaptureLogge
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的实例?只要您使用Lombok生成记录器,您就无法使用给定的工具在源代码本身的级别上做很多工作。例如,如果放置
@Log4j2
注释,它将生成:
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
这行代码已经编译好了
您可以尝试使用PowerMockito模拟LogManager.getLogger方法,但我并不真正喜欢这种工具。尽管如此,这是一个可行的方向
使用框架本身有两种方法
一种方法(我不太熟悉Log4j2,但它应该提供这种功能——我在很多年前做了类似于log4j1.x的事情)是提供您自己的logger实现,并在Log4j2配置级别将其与logger工厂相关联。
现在,如果您这样做,那么lombok生成的代码将返回您的logger实例,该实例可以记住在不同级别记录的消息(这是您必须在logger级别实现的自定义逻辑)
然后记录器将有一个方法public List 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");
}
只要您使用Lombok生成日志,您就无法使用给定的工具在源代码本身的级别上做很多工作。例如,如果放置
@Log4j2
注释,它将生成:
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
这行代码已经编译好了
您可以尝试使用PowerMockito模拟LogManager.getLogger方法,但我并不真正喜欢这种工具。尽管如此,这是一个可行的方向
使用框架本身有两种方法
一种方法(我不太熟悉Log4j2,但它应该提供这种功能——我在很多年前做了类似于log4j1.x的事情)是提供您自己的logger实现,并在Log4j2配置级别将其与logger工厂相关联。
现在,如果您这样做,那么lombok生成的代码将返回您的logger实例,该实例可以记住在不同级别记录的消息(这是您必须在logger级别实现的自定义逻辑)
然后记录器将有一个方法public List 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");
}
您可以这样定义自己的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");
}
package com.xyz;
导入静态java.util.Collections.synchronizedList;
导入java.util.ArrayList;
导入java.util.List;
导入org.apache.logging.log4j.core.Appender;
导入org.apache.logging.log4j.core.Filter;
导入org.apache.logging.log4j.core.LogEvent;
导入org.apache.logging.log4j.core.appender.AbstractAppender;
导入org.apache.logging.log4j.core.config.plugins.Plugin;
导入org.apache.logging.log4j.core.config.plugins.PluginAttribute;
导入org.apache.logging.log4j.core.config.plugins.PluginElement;
导入org.apache.logging.log4j.core.config.plugins.PluginFactory;
@插件(name=“logstolistpappender”,category=“Core”,elementType=Appender.ELEMENT\u TYPE)
公共类LogsToListAppender扩展了AbstractAppender{
私有静态最终列表事件=synchronizedList(新ArrayList());
受保护的LogsToListAppender(字符串名称、筛选器){
super(名称、筛选器、空);
}
@插件工厂
公共静态LogsToListAppender createAppender(@PluginAttribute(“name”)字符串名,
@插件(“过滤器”)过滤器(过滤器){
返回新的LogsToListAppender(名称、过滤器);
}
@凌驾
公共无效附加(LogEvent事件){
事件。添加(事件);
}
公共静态列表getEvents(){
返回事件;
}
}
然后在类路径的根目录中创建一个名为log4j2 logstolist.xml的文件,该类路径将引用appender:
最后创建TestNG测试:
package com.xyz;
导入静态org.testng.Assert.assertTrue;
导入org.apache.logging.log4j.LogManager;
导入org.apache.logging.log4j.core.config.Configurator;
导入org.testng.annotations.Test;
@试验
公共类日志{
静止的{
初始化(null,“classpath:log4j2 logstolist.xml”);
}
@试验
公共void测试日志(){
//调用生成日志的代码,例如。
LogManager.getLogger(LogsTest.class).trace(“Hello”);
assertTrue(LogsToListAppender.getEvents().size()>0);
}
}
如您所见,我们正在强制Log4j2使用带有Configurator.initialize的自定义配置(null,“classpath:Log4j2 logstolist.xml”)初始化类时(static{}
block)
请记住,检查记录器名称对您也很有用,例如,LogsToListAppender.getEvents().stream().filter(a->CLASS_,它生成_LOG.CLASS.getName().equals(a.getLoggerName()).collect(toList())代码>
您可以使用LogEvent::getMessage()
方法访问实际消息您可以这样定义自己的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");
}
package com.xyz;
导入静态java.util.Collections.synchronizedList;
导入java.util.ArrayList;
导入java.util.List;
导入org.apache.logging.log4j.core.Appender;
导入org.ap