Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log4J with JUnit Tests

I would like to add logging to my Selenium Java tests. I have implemented the log4jFramework which works well either placing the logs in the console or in a file.

I am using the JUnit test framework and I would like to include the test name and date/time in the filename of the logfile rather than using the standard convention which seems to be to prepend a number +1 to the file if a file already exists.

This is my log4j.properties file...

log4j.appender.rollingFile=org.apache.log4j.RollingFileAppender
log4j.appender.rollingFile.File=~/Desktop/Selenium/AutomationLogs/automationLog
log4j.appender.rollingFile.MaxFileSize=2MB
log4j.appender.rollingFile.MaxBackupIndex=2
log4j.appender.rollingFile.layout = org.apache.log4j.PatternLayout
log4j.appender.rollingFile.layout.ConversionPattern=%d{dd MMM yyyy HH:mm:ss} %p %t %c - %m%n

What I have found online only seems relevant to daily rolling files. I would like to generate a new file for the logs every time I run a unit test

like image 403
Daniel Cohen Avatar asked May 10 '15 14:05

Daniel Cohen


1 Answers

If I understand your needs correctly this can be achieved by combining the following:

  • using a JUnit method rule which will give you the name of the current method
  • creating a Log4j appender at runtime, and configuring it with the name of the method obtained you just obtained

Specifically, you need to create a custom JUnit rule. I chose to extend the TestWatcher as it seems most appropriate

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.RollingFileAppender;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;

public class TestMethodLogging extends TestWatcher {
  private static final String date = new SimpleDateFormat("y-MM-dd")
      .format(new Date());
  private Logger logger;

  @Override
  protected void starting(Description description) {
    String name = description.getMethodName();
    RollingFileAppender a = (RollingFileAppender) Logger.getRootLogger()
        .getAppender("rollingFile");
    PatternLayout layout = new PatternLayout();
    layout.setConversionPattern("%d{dd MMM yyyy HH:mm:ss} %p %t %c - %m%n");

    try {
      File logDir = new File(a.getFile()).getParentFile();
      File logFile = new File(logDir, name + "_" + date);
      logger = Logger.getLogger(name);
      logger.addAppender(new RollingFileAppender(layout, logFile
          .getAbsolutePath()));
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public Logger getLogger() {
    return logger;
  }
}

Once you have this you can place it as a rule inside your test class. A rule is simply a field in the test (carrying the @Rule annotation). In here I called it rule (not very imaginative, I admit). In order to log from your test method you need to call rule.getLogger().

import static org.junit.Assert.assertEquals;

import org.junit.Rule;
import org.junit.Test;

public class MyTest {
  @Rule
  public TestMethodLogging rule = new TestMethodLogging();

  @Test
  public void sumOfTwoInts() throws Throwable {
    rule.getLogger().error(
        "logging to a logger whose name is based on the test method's name");
    assertEquals(5, 2 + 3);
  }

  @Test
  public void productOfTwoInts() throws Throwable {
    rule.getLogger().error(
        "logging to a logger whose name is based on the test method's name");
    assertEquals(8, 2 * 4);
  }
}

When I run this test it creates these two files under my ~/Desktop/Selenium/AutomationLogs directory:

productOfTwoInts_2015-05-10  
sumOfTwoInts_2015-05-10

The content of the first file looks as follows:

$ cat productOfTwoInts_2015-05-10 
10 May 2015 19:59:58 ERROR main productOfTwoInts - logging to a logger whose name is based on the test method's name
10 May 2015 20:01:22 ERROR main productOfTwoInts - logging to a logger whose name is based on the test method's name
10 May 2015 20:01:24 ERROR main productOfTwoInts - logging to a logger whose name is based on the test method's name
like image 59
Itay Maman Avatar answered Oct 05 '22 16:10

Itay Maman