1

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 confirm that the correct log entry was made in this logger. For example; I have 2 Error Logs for two separate conditions.

methodGoingToBeTested(bool a, bool b){
    if(a)
        logger.info("a happened")
    else()
        logger.info("b happened")

}

@Test tester(){

    methodGoingToBeTested(true);
    assertXXXXXX(loggedLevel(),Level.INFO);
}

I would like to test to see if the Logger error's I have up on the actual method generates accurately upon the condition it is meant to generate at. I have checked online but the advice is really old. Does anyone have any suggestions? Your help is appreciated.

I know there is a similar post here but that post is really outdated and the same process can not be used now to solve this problem, which is why I am asking this question in the first place.

Ferdz
  • 69
  • 1
  • 2
  • 6
  • what logger are you using? log4j? – TruckDriver Dec 12 '17 at 12:06
  • Yes I have tried using log4j although no luck – Ferdz Dec 12 '17 at 12:07
  • That post was really dated and the advice on it was really old and I have tried everything mentioned on that post although no luck, which is why I asked it – Ferdz Dec 12 '17 at 12:08
  • I was faced with this problem, and found this solution that helped me: https://stackoverflow.com/a/8708357/9210263 Basically diverging console contents to a String. – LeYAUable Jan 14 '20 at 16:24

1 Answers1

2

The reason you're not able to test this is, presumably, because you instantiate the logger within the class you're testing.

class MyClass
{
    private final Logger logger = /* whatever */;
}

If, instead, you use dependency injection you'll allow yourself to be able to test this behaviour.

class MyClass
{
    private final Logger logger;

    MyClass(final Logger logger)
    {
        this.logger = logger;
    }
}

Now, in your test, you inject a mock or fake logger. Here's a simple example using Mockito:

@Mock
Logger logger;

@Test
void tester()
{
    MyClass inst = new MyClass(logger);

    methodUnderTest(true);

    BDDMockito.verify(logger).info(Mockito.anyString());
}

You could perform a more strict verification if you wanted.

Equally, you could create a fake Logger implementation for the purposes of the test which performs the required assertions, rather than mocking. Here's a very basic example:

class FakeLogger implements Logger
{
    private boolean hasInfoBeenCalled = false;

    @Override
    public void info(String message)
    {
        hasInfoBeenCalled = true;
    }

    // Other Logger methods...

    public boolean hasInfoBeenCalled()
    {
        return hasInfoBeenCalled;
    }
}

@Test
void tester()
{
    FakeLogger logger = new FakeLogger();
    MyClass inst = new MyClass(logger);

    methodUnderTest(true);

    Assert.assertTrue(logger.hasInfoBeenCalled());
}

All that being said, I would carefully re-think the design of your class if the only observable and testable behaviour is writing to a log file. If you decide to change the logging in future, you may well find that your tests are very brittle.

Michael
  • 41,989
  • 11
  • 82
  • 128