6

I see that loggers have been mocked with help of Powermock or some sort of overridden constructor which takes logger.

Being logger used all over the code, is not their a simple way using just mockito? Some way to ignore the call or mock it - I do not want to validate any message, just want to avoid the Null Pointer exception

I am new to mocking frameworks so I am wondering rather use Jmockit instead of mixing and matching two libraries -The only reason to avoid jomockit so far -its just too power full and can easily be misused!

splatte
  • 2,048
  • 1
  • 15
  • 18
cpandey05
  • 1,241
  • 2
  • 17
  • 30
  • 2
    Why do you need to mock the loggers? Why not just let the logging happen? You can set up a test configuration for logging that would prevent a file from being written (for example just send all logging to the console). – John B Oct 17 '13 at 15:33
  • 1
    Hmm, Simple and better Idea. – cpandey05 Oct 18 '13 at 05:58

1 Answers1

4

I use verification of logs in cases where I think that it is very important to log at a certain level. This is how I do it using Mockito:

Utility Class

public final class LoggingTestUtil {

    private LoggingTestUtil() {
    }

    public static void setupLoggingMock(Logger logger, Appender<ILoggingEvent> appender) {
        logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
        when(appender.getName()).thenReturn("MOCK");
        logger.addAppender(appender);
    }

    public static void verifyLogAppended(Appender<ILoggingEvent> appender, final String loggedString) {
        verify(appender).doAppend(argThat(new ArgumentMatcher<LoggingEvent>() {
            @Override
            public boolean matches(final Object argument) {
                return ((LoggingEvent) argument).getMessage().contains(loggedString);
            }
        }));
    }

    public static void verifyLogAppendedAtLevel(Appender<ILoggingEvent> appender, final Level level) {
        verify(appender).doAppend(argThat(new ArgumentMatcher<LoggingEvent>() {
            @Override
            public boolean matches(final Object argument) {
                return ((LoggingEvent) argument).getLevel().equals(level);
            }
        }));
    }

    public static void verifyLogAppendedAtLevel(Appender<ILoggingEvent> appender, final Level level, final String loggedString) {
        verify(appender).doAppend(argThat(new ArgumentMatcher<LoggingEvent>() {
            @Override
            public boolean matches(final Object argument) {
                LoggingEvent event = (LoggingEvent) argument;
                return event.getLevel().equals(level) && event.getMessage().contains(loggedString);
            }
        }));
    }
}

In Test Class

private static Logger root;
@Mock
private static Appender<ILoggingEvent> mockAppender; // used to test that logging occurs

    @Test
    public final void testSomething(){
        LoggingTestUtil.setupLoggingMocks(root, mockAppender);
        underTest.doSomethingBad();
        LoggingTestUtil.verifyLogAppendedAtLevel(mockAppender, Level.ERROR, "bad thing");
    }
Dennis
  • 3,683
  • 1
  • 21
  • 43
  • 3
    I believe that mocking is a poor strategy for log verification as it is brittle and is overkill. I have created a JUnit Rule that adds an temporary appender to the default logger in log4j. This then allows for verification of logging simply by adding the Rule to the test. https://github.com/dancerjohn/LibEx/blob/master/testlibex/src/main/java/org/libex/test/logging/log4j/Log4jCapturer.java – John B Oct 17 '13 at 16:50
  • @JohnB - Interesting... Will check it out. I do find this solution brittle as it breaks when the Level/string changes. However would a rule not be exactly the same in that regard? By overkill do you mean that the mocks would be a lot more heavyweight? I'm relatively new to mocking so very interested to know. :) – Dennis Oct 17 '13 at 17:08
  • 1. Yes the mocks are much more heavyweight and the expected method calls must be configured. 2. The test would fail ONLY if the logging level was part of the verification. If you expect an ERROR message and it was an INFO if will fail. If you expect a message at any level then it would not fail. – John B Oct 17 '13 at 18:03