Question: I have some code-under-test that calls on a Java logger to report its status.
In the JUnit test code, I would like to verify that the correct log entry was made in this logger. Something along the following lines:

```
methodUnderTest(bool x){
    if(x)
        logger.info("x happened")
}

@Test tester(){
    // perhaps setup a logger first.
    methodUnderTest(true);
    assertXXXXXX(loggedLevel(),Level.INFO);
}

```

I suppose that this could be done with a specially adapted logger (or handler, or formatter), but I would prefer to re-use a solution that already exists. (And, to be honest, it is not clear to me how to get at the logRecord from a logger, but suppose that that's possible.)

Answer: 
As mentioned from the others you could use a mocking framework. For this to make work you have to expose the logger in your class (although I would propably prefere to make it package private instead of creating a public setter).

The other solution is to create a fake logger by hand. You have to write the fake logger (more fixture code) but in this case I would prefer the enhanced readability of the tests against the saved code from the mocking framework.

I would do something like this:

```
class FakeLogger implements ILogger {
    public List<String> infos = new ArrayList<String>();
    public List<String> errors = new ArrayList<String>();

    public void info(String message) {
        infos.add(message);
    }

    public void error(String message) {
        errors.add(message);
    }
}

class TestMyClass {
    private MyClass myClass;        
    private FakeLogger logger;        

    @Before
    public void setUp() throws Exception {
        myClass = new MyClass();
        logger = new FakeLogger();
        myClass.logger = logger;
    }

    @Test
    public void testMyMethod() {
        myClass.myMethod(true);

        assertEquals(1, logger.infos.size());
    }
}

```
If you are using log4j2, the solution from <https://www.dontpanicblog.co.uk/2018/04/29/test-log4j2-with-junit/> allowed me to assert messages were logged.

The solution goes like this:

* Define a log4j appender as an ExternalResource rule

```
public class LogAppenderResource extends ExternalResource {

private static final String APPENDER_NAME = "log4jRuleAppender";

/**
 * Logged messages contains level and message only.
 * This allows us to test that level and message are set.
 */
private static final String PATTERN = "%-5level %msg";

private Logger logger;
private Appender appender;
private final CharArrayWriter outContent = new CharArrayWriter();

public LogAppenderResource(org.apache.logging.log4j.Logger logger) {
    this.logger = (org.apache.logging.log4j.core.Logger)logger;
}

@Override
protected void before() {
    StringLayout layout = PatternLayout.newBuilder().withPattern(PATTERN).build();
    appender = WriterAppender.newBuilder()
            .setTarget(outContent)
            .setLayout(layout)
            .setName(APPENDER_NAME).build();
    appender.start();
    logger.addAppender(appender);
}

@Override
protected void after() {
    logger.removeAppender(appender);
}

public String getOutput() {
    return outContent.toString();
    }
}

```
* Define a test that use your ExternalResource rule

```
public class LoggingTextListenerTest {

    @Rule public LogAppenderResource appender = new LogAppenderResource(LogManager.getLogger(LoggingTextListener.class)); 
    private LoggingTextListener listener = new LoggingTextListener(); //     Class under test

    @Test
    public void startedEvent_isLogged() {
    listener.started();
    assertThat(appender.getOutput(), containsString("started"));
    }
}

```

Don't forget to have log4j2.xml as part of src/test/resources