title: Log4j2 Mock Appender
body: <p>I have a class in which I take all of my Properties, and hide their passwords before logging.</p>
  
  <pre><code>@Override
  public void afterPropertiesSet() throws Exception {
      Properties loadedProperties = this.mergeProperties();
      loadedProperties.entrySet().stream().forEach(singleProperty -&gt; {
          String key = singleProperty.getKey().toString();
          String value = HIDDEN_VALUE;
  
          if (!Arrays.stream(PASSWORD_PATTERNS).anyMatch(pattern -&gt; key.toLowerCase().contains(pattern))) {
              value = singleProperty.getValue().toString();                  
          }
  
          logger.info("LoadedProperty: "+ key +"=" + value);
      });
  }
  </code></pre>
  
  <p>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 </p>
  
  <blockquote>
    <p>Wanted but not invoked:
    mockAppender.append();
    -> at com.comp.spmConf.ExceptionLoggerTest.verifyErrorMessages(ExceptionLoggerTest.java:87)</p>
    
    <p>However, there were other interactions with this mock:
    mockAppender.getName();
    -> at org.apache.logging.log4j.core.config.AbstractConfiguration.addLoggerAppender(AbstractConfiguration.java:675)</p>
    
    <p>mockAppender.getName();
    -> at org.apache.logging.log4j.core.config.AppenderControl.(AppenderControl.java:51)</p>
  </blockquote>
  
  <p>Here is my log4j1 test class:</p>
  
  <pre><code>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());
  }
  
  }
  </code></pre>
  
  <p>And here is my log4j2 test class, am I doing something wrong in the log4j to log4j2 migration?</p>
  
  <pre><code>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&lt;LogEvent&gt; 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());
      }
  }
  </code></pre>