我创建了几个自定义记录器,其某些级别覆盖了 Log4J2 中的自定义记录器。我已按照 http://logging.apache.org/log4j/2.x/manual/customloglevels.html.
上的指南进行操作我需要创建一些单元测试来验证事件是否在正确的自定义级别和配置上注册。
我很感激任何有关如何开始的提示。非常感谢。
您可以看到我在其中一项 JUnit 测试中所做的事情。
1- 创建一个自定义附加程序,在内存中保存消息列表。
package com.example.appender;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.Property;
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;
import org.apache.logging.log4j.core.layout.PatternLayout;
/**
* @author carrad
*
*/
@Plugin(name = "TestAppender", category = "Core", elementType = "appender", printObject = true)
public class TestAppender extends AbstractAppender {
@Getter
private final List<LogEvent> messages = new ArrayList<>();
protected TestAppender(String name, Filter filter, Layout<? extends Serializable> layout) {
super(name, filter, layout, true, Property.EMPTY_ARRAY);
}
@Override
public void append(LogEvent event) {
messages.add(event);
}
@PluginFactory
public static TestAppender createAppender(
@PluginAttribute("name") String name,
@PluginElement("Layout") Layout<? extends Serializable> layout,
@PluginElement("Filter") final Filter filter,
@PluginAttribute("otherAttribute") String otherAttribute
) {
if (name == null) {
LOGGER.error("No name provided for TestAppender");
return null;
}
if (layout == null) {
layout = PatternLayout.createDefaultLayout();
}
return new TestAppender(name, filter, layout);
}
}
2- 将附加程序添加到
log4j2-test.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="com.example.appender">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</Console>
<TestAppender name="TestAppender" >
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</TestAppender>
</Appenders>
<Loggers>
<Logger name="com.example" level="All" />
<Root>
<AppenderRef ref="Console" level="All" />
<AppenderRef ref="TestAppender" level="All" />
</Root>
</Loggers>
</Configuration>
3- 在 Junit 测试中获取对 Appender 的引用。
public class LoggingInterceptorTest {
@Autowired // Whatever component you want to test
private InterceptedComponent helperComponent;
private TestAppender appender;
@Before
public void setUp() {
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
appender = (TestAppender) config.getAppenders().get("TestAppender");
}
@Test
public void test_wrapping() {
helperComponent.doStuff("437");
Assert.assertEquals(appender.getMessages().size(), 2);
}
}
在您的测试用例中,您可以检查写入的消息数量或包含您想要的消息的列表,包括级别等元信息。
我建议查看 log4j2 中的 JUnit 测试。
许多log4j2单元测试使用带有immediateFlush = true的FileAppender,然后读取文件并检查输出中是否存在一些预期的字符串。其他人配置一个(org.apache.logging.log4j.test.appender。)ListAppender(此类位于核心测试 jar 中)并直接从列表中获取 LogEvent 对象。
您可能需要为 log4j2 JUnit 测试创建一个新进程,以确保之前的进程尚未加载不同的配置。
一种选择是使用自定义的 OutputStreamAppender 子类将记录器配置为写入内存中的字符串(字节数组)流,您必须对其进行编码。
然后,您可以在测试中对结果字符串使用断言。
我最近在这里发表了一篇关于这样做的博文。也许它会对你有帮助。
这是如何测试日志记录的示例。此代码基于 log4j
存储库中的
示例测试。我添加了一个将消息保存到
StringWriter
的附加程序。在我的测试环境中,有一个消息转换器可以屏蔽敏感信息,我的测试使用它,即使我没有描述它的配置,并且测试用例演示了它。
package org.cyberpro.debate.integration.logger_config;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.WriterAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.slf4j.LoggerFactory;
import java.io.StringWriter;
import java.lang.reflect.Method;
final class TestLogger {
private StringWriter writer;
private String testMethodName;
@BeforeEach
void setUp(final TestInfo testInfo) {
testMethodName = testInfo.getTestMethod().map(Method::getName).orElseGet(testInfo::getDisplayName);
prepareAppender(testMethodName);
}
void prepareAppender(String writerName) {
writer = new StringWriter();
final LoggerContext context = LoggerContext.getContext(false);
final Configuration config = context.getConfiguration();
final PatternLayout layout = PatternLayout.newBuilder()
.withConfiguration(config)
.withPattern("%spi%n")
.build();
final Appender appender = WriterAppender.createAppender(layout, null, writer, writerName, false, true);
appender.start();
config.addAppender(appender);
updateLoggers(appender, config);
}
void updateLoggers(final Appender appender, final Configuration config) {
for (final LoggerConfig loggerConfig : config.getLoggers().values()) {
loggerConfig.addAppender(appender, Level.ERROR, null);
}
config.getRootLogger().addAppender(appender, Level.ERROR, null);
}
@Test
void name1() {
final Logger logger = LogManager.getLogger(testMethodName);
logger.error("Test message");
logger.error("1234564564546456466466");
Assertions.assertThat(writer.toString())
.contains("Test message")
.contains("1234**************6466");
}
@Test
void slf4j_test() {
LoggerFactory.getLogger(getClass()).error("slf4j_test");
Assertions.assertThat(writer.toString())
.contains("slf4j_test")
.doesNotContain("Test message");
}
}