Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log4j2 Mock Appender

I have a class in which I take all of my Properties, and hide their passwords before logging.

@Override
public void afterPropertiesSet() throws Exception {
    Properties loadedProperties = this.mergeProperties();
    loadedProperties.entrySet().stream().forEach(singleProperty -> {
        String key = singleProperty.getKey().toString();
        String value = HIDDEN_VALUE;

        if (!Arrays.stream(PASSWORD_PATTERNS).anyMatch(pattern -> key.toLowerCase().contains(pattern))) {
            value = singleProperty.getValue().toString();                  
        }

        logger.info("LoadedProperty: "+ key +"=" + value);
    });
}

I have migrated to log4j2 and would like to test this class, checking the output of log4j2. It currently uses log4j and works, however when I migrated to log4j2, I get

Wanted but not invoked: mockAppender.append(); -> at com.comp.spmConf.ExceptionLoggerTest.verifyErrorMessages(ExceptionLoggerTest.java:87)

However, there were other interactions with this mock: mockAppender.getName(); -> at org.apache.logging.log4j.core.config.AbstractConfiguration.addLoggerAppender(AbstractConfiguration.java:675)

mockAppender.getName(); -> at org.apache.logging.log4j.core.config.AppenderControl.(AppenderControl.java:51)

Here is my log4j1 test class:

import org.apache.log4j.Appender;
import org.apache.log4j.LogManager;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Properties;

@RunWith(MockitoJUnitRunner.class)
public class SpmPropertyTracerTest {

@Mock
private Appender appenderMock;

@Captor
private ArgumentCaptor captorLoggingEvent;

private SpmPropertyTracer tracer;

@Before
public void setup() {
    LogManager.getRootLogger().addAppender(appenderMock);
    tracer = new SpmPropertyTracer();
}

@After
public void teardown() {
    LogManager.getRootLogger().removeAppender(appenderMock);
}

@Test
public void printPropertiesTest() throws Exception{
    String key1 = "Foo";
    String val1 = "True";
    Properties properties = new Properties();
    properties.setProperty(key1, val1);
    tracer.setProperties(properties);
    String expectedString = String.format("LoadedProperty: %s=%s", key1, val1);
    tracer.afterPropertiesSet();
    Mockito.verify(appenderMock).doAppend((LoggingEvent)captorLoggingEvent.capture());
    LoggingEvent loggingEvent = (LoggingEvent) captorLoggingEvent.getValue();
    assert expectedString.equals(loggingEvent.getRenderedMessage());
}

}

And here is my log4j2 test class, am I doing something wrong in the log4j to log4j2 migration?

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.Logger;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.Properties;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;



@RunWith(MockitoJUnitRunner.class)
public class TestClass {
@Mock
private Appender mockAppender;
@Captor
private ArgumentCaptor<LogEvent> captorLoggingEvent;

private SpmPropertyTracer tracer;

private Logger logger;

private LogEvent logEvent;

@Before
public void setup() {
    // prepare the appender so Log4j likes it
    when(mockAppender.getName()).thenReturn("MockAppender");
    when(mockAppender.isStarted()).thenReturn(true);
    when(mockAppender.isStopped()).thenReturn(false);

    logger = (Logger)LogManager.getLogger(SpmPropertyTracer.class);
    logger.addAppender(mockAppender);
    logger.setLevel(Level.INFO);

    tracer = new SpmPropertyTracer();
}

@After
public void tearDown() {
    // the appender we added will sit in the singleton logger forever
    // slowing future things down - so remove it
    logger.removeAppender(mockAppender);
}

@Test
public void loggingIsCaptured() throws Exception {
    String key1 = "Foo";
    String val1 = "True";
    Properties properties = new Properties();
    properties.setProperty(key1, val1);
    tracer.setProperties(properties);
    String expectedString = String.format("LoadedProperasdfty: %s=%s", key1, val1);
    tracer.afterPropertiesSet();
    verifyErrorMessages(expectedString);
}


// handy function to inspect the messages sent to the logger
private void verifyErrorMessages(String ... messages) {
    verify(mockAppender, times(messages.length)).append((LogEvent)captorLoggingEvent.capture());

    int i=0;
    for(LogEvent loggingEvent:captorLoggingEvent.getAllValues()) {
        assertEquals(messages[i++], loggingEvent.getMessage().getFormattedMessage());
    }
}
like image 599
DevelopingDeveloper Avatar asked Feb 07 '17 18:02

DevelopingDeveloper


1 Answers

The parent project was brining in a log4j dependency, thus slf4j was binding with log4j and not log4j2 and that is why the append method was not invoked. Removing that dependency fixed my errors.

like image 139
DevelopingDeveloper Avatar answered Sep 27 '22 22:09

DevelopingDeveloper