javaloggingjunitassert

How to do a JUnit assert on a message in a logger


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(boolean x) {
    if(x) { logger.info("x happened"); }
}

@Test tester() {
    // perhaps set up 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 reuse 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.)


Solution

  • Thanks a lot for these (surprisingly) quick and helpful answers; they put me on the right way for my solution.

    The codebase were I want to use this, uses java.util.logging as its logger mechanism, and I don't feel at home enough in those codes to completely change that to log4j or to logger interfaces/facades. But based on these suggestions, I 'hacked-up' a j.u.l.handler extension and that works as a treat.

    A short summary follows. Extend java.util.logging.Handler:

    class LogHandler extends Handler
    {
        Level lastLevel = Level.FINEST;
    
        public Level  checkLevel() {
            return lastLevel;
        }    
    
        public void publish(LogRecord record) {
            lastLevel = record.getLevel();
        }
    
        public void close(){}
        public void flush(){}
    }
    

    Obviously, you can store as much as you like/want/need from the LogRecord, or push them all into a stack until you get an overflow.

    In the preparation for the junit-test, you create a java.util.logging.Logger and add such a new LogHandler to it:

    @Test tester() {
        Logger logger = Logger.getLogger("my junit-test logger");
        LogHandler handler = new LogHandler();
        handler.setLevel(Level.ALL);
        logger.setUseParentHandlers(false);
        logger.addHandler(handler);
        logger.setLevel(Level.ALL);
    

    The call to setUseParentHandlers() is to silence the normal handlers, so that (for this junit-test run) no unnecessary logging happens. Do whatever your code-under-test needs to use this logger, run the test and assertEquality:

        libraryUnderTest.setLogger(logger);
        methodUnderTest(true);  // see original question.
        assertEquals("Log level as expected?", Level.INFO, handler.checkLevel() );
    }
    

    (Of course, you would move large part of this work into a @Before method and make assorted other improvements, but that would clutter this presentation.)