How can I test with junit that a warning was logged with log4j?

Asaf picture Asaf · Sep 15, 2010 · Viewed 67.7k times · Source

I'm testing a method that logs warnings when something went wrong and returns null.
something like:

private static final Logger log = Logger.getLogger(Clazz.class.getName());
....
if (file == null || !file.exists()) {
  // if File not found
  log.warn("File not found: "+file.toString());
} else if (!file.canWrite()) {
  // if file is read only
  log.warn("File is read-only: "+file.toString());
} else {
  // all checks passed, can return an working file.
  return file;
}
return null;

i'd like to test with junit that a warning was issued, in addition to returning null, in all cases (e.g. file not found, file is read-only).
any ideas?
thanks, asaf :-)


UPDATE

My implementation of Aaron's answer (plus peter's remark):

public class UnitTest {
...

@BeforeClass
public static void setUpOnce() {
  appenders = new Vector<Appender>(2);
  // 1. just a printout appender:
  appenders.add(new ConsoleAppender(new PatternLayout("%d [%t] %-5p %c - %m%n")));
  // 2. the appender to test against:
  writer = new StringWriter();
  appenders.add(new WriterAppender(new PatternLayout("%p, %m%n"),writer));
}

@Before
public void setUp() {
  // Unit Under Test:
  unit = new TestUnit();
  // setting test appenders:
  for (Appender appender : appenders) {
    TestUnit.log.addAppender(appender);
  }
  // saving additivity and turning it off:
  additivity = TestUnit.log.getAdditivity();
  TestUnit.log.setAdditivity(false);
}

@After
public void tearDown() {
  unit = null;
  for (Appender appender : appenders) {
    TestUnit.log.removeAppender(appender);
  }
  TestUnit.log.setAdditivity(additivity);
}

@Test
public void testGetFile() {
  // start fresh:
  File file;
  writer.getBuffer().setLength(0);

  // 1. test null file:
  System.out.println(" 1. test null file.");
  file = unit.getFile(null);
  assertNull(file);
  assertTrue(writer.toString(), writer.toString().startsWith("WARN, File not found"));
  writer.getBuffer().setLength(0);

  // 2. test empty file:
  System.out.println(" 2. test empty file.");
  file = unit.getFile("");
  assertNull(file);
  assertTrue(writer.toString(), writer.toString().startsWith("WARN, File not found"));
  writer.getBuffer().setLength(0);
}

thanks guys,

Answer

Aaron Digulla picture Aaron Digulla · Sep 15, 2010

In the setup of the unit test:

  1. Get the same logger
  2. Make it non-additive
  3. Add an appender which remembers the messages in a list:

    public class TestAppender extends AppenderSkeleton {
        public List<String> messages = new ArrayList<String>();
    
        public void doAppend(LoggingEvent event) {
            messages.add( event.getMessage().toString() );
        }
    }
    
  4. Add the appender to the logger

Now you can call your code. After the test, you will find all log messages in the list. Add the log level if you want (messages.add( event.getLevel() + " " + event.getMessage() );).

In tearDown(), remove the appender again and enable additivity.