JUnit 実行で、ログファイルをテストケース毎に保存させる。

org.junit.rules.TestName から実行時のテストケースメソッド名を取得して
メソッド名のディレクトリにログ出力をテストケース単位にログファイルとして保存します。

SL4J + log4j2 を使用している場合と、SL4J + logback を使用している場合、
各々退避方法に工夫が必要です。

SL4J + log4j2 を使用している場合、

log4j2.xml に対してテストで使用する test-log4j2.xml が以下であるとします。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn">
   <Properties>
      <Property name="format1">[%d{yyyy-MM-dd HH:mm:ss.SSS}],[%-5p], %c, %m%n</Property>
   </Properties>
   <Appenders>
      <Console name="Console" target="SYSTEM_OUT">
         <PatternLayout>
            <pattern>${format1}</pattern>
         </PatternLayout>
      </Console>
      <!-- ########## test-log4j2.xml だけに記載する ############ -->
      <File name="file" fileName="/work/console.log">
         <PatternLayout>
            <pattern>${format1}</pattern>
         </PatternLayout>
      </File>
      <!-- ##################################################### -->
   </Appenders>
   <Loggers>
      <Root level="trace">
         <AppenderRef ref="Console" />
         <!-- ########## test-log4j2.xml だけに記載する ############ -->
         <AppenderRef ref="file" />
         <!-- ##################################################### -->
      </Root>

      <Logger name="org.apache.ibatis.transaction" level="WARN" />
      <Logger name="org.mybatis.guice.transactional" level="WARN" />

      <Logger name="org.myproject" level="INFO" />
   </Loggers>
</Configuration>

JUnit のソース
@BeforeClass メソッド=このJUnitインスタンス生成時だけ動くメソッドで
test-log4j2.xml で書いた "file" の FileAppender を探し出して、
コンソール標準出力したログファイルパスを記憶させます。
@After メソッドで
LogManager.shutdown(); による一時的なログ出力の中断を発生させて、、
記憶させたログファイルパスから、org.junit.rules.TestName で取得する
テストケースメソッド名に沿って、ログファイルを移動します。

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.FileAppender;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class SampleTest{
    private static String logfilepath;
    @Rule  public TestName testName = new TestName();

    @BeforeClass
    public static void initialize(){
        System.setProperty("log4j.configurationFile", "test-log4j2.xml");
        try(LoggerContext ctx = (LoggerContext) LogManager.getContext()){
             logfilepath = ((FileAppender)ctx.getConfiguration().getAppender("file")).getFileName();
        }
    }

    @Before
    public void before() {
        // TODO
    }
    @After
    public void after() {
        // LogManager shutdown
        LogManager.shutdown();
        // 退避先を生成
        File testOutDir = new File("/logrecord/" + testName.getMethodName());
        testOutDir.mkdirs();
        // ログファイルを移動
        try{
            Files.move(Paths.get(logfilepath), Paths.get(testOutDir.getAbsolutePath() + "/console.log"), StandardCopyOption.REPLACE_EXISTING);
        }catch(IOException e){
            e.printStackTrace();
            Assert.fail();
        }
    }
    @Test
    public void test1() {
        // TODO
    }
    @Test
    public void test2() {
        // TODO
    }
}

これで、/logrecord/test1/console.log と /logrecord/test2/console.log が保存されます。

SL4J + logback を使用している場合、

logback.xml に対してテストで使用する test-logback.xml が以下であるとします。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE logback>
<configuration>
   <statusListener class="ch.qos.logback.core.status.NopStatusListener" />
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <Target>System.out</Target>
      <encoder>
         <Pattern>%-23d{yyyy/MM/dd HH:mm:ss.SSS} %-5p [%thread] %m\t\t\t[%C{0}.%method:%line]%n</Pattern>
      </encoder>
   </appender>
   <!-- ########## test-logback.xml だけに記載する ###################################### -->
   <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <File>/work/console.log</File>
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
         <FileNamePattern>/var/log/labo.%d{yyyy-MM-dd}.log</FileNamePattern>
         <maxHistory>6</maxHistory>
      </rollingPolicy>
      <encoder>
         <charset>UTF-8</charset>
         <Pattern>%-23d{yyyy/MM/dd HH:mm:ss.SSS} %-5p [%thread] %m\t\t\t[%C{0}.%method]%n</Pattern>
      </encoder>
   </appender>
   <!-- ################################################################################# -->

   <logger name="org.myproject">
      <level value="debug" />
      <appender-ref ref="STDOUT" />
      <!-- ########## test-logback.xml だけに記載する ###################################### -->
      <appender-ref ref="FILE" />
      <!-- ################################################################################# -->
   </logger>

</configuration>

log4j2 のような、LogManager shutdown がありません。
テストケースの @After で、ファイルコピー後に、空文字でログファイルを上書きするという
ちょっとセンスがない方法しかないようです。
FileAppender を探索する方法もちょっと面倒な方法をしなければなりません。

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Iterator;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.FileAppender;
@RunWith(JUnit4.class)
public class SampleTest{
    @Rule  public TestName testName = new TestName();
    private static File appenderFile;

    @BeforeClass
    public static void initialize(){
        System.setProperty("logback.configurationFile","test-logback.xml");
        // FileAppenderを探索して、ログ Fileを求める
        appenderFile = getAppenderFile("FILE");
    }

    @Before
    public void before() {
        // TODO
    }
    @After
    public void after() {
        // 退避先を生成
        File testOutDir = new File("/logrecord/" + testName.getMethodName());
        testOutDir.mkdirs();
        // コピーで退避
        try{
            Files.copy(Paths.get(appenderFile.getAbsolutePath()), Paths.get(testOutDir.getAbsolutePath() + "/console.log"), StandardCopyOption.REPLACE_EXISTING);
        }catch(IOException e){
            e.printStackTrace();
            Assert.fail();
        }
        // ログファイルを空文字で上書きする
        try(FileWriter writer = new FileWriter(appenderFile)){
            writer.write("");
            writer.flush();
        }catch(IOException e){
            e.printStackTrace();
            Assert.fail();
        }
    }
    private static File getAppenderFile(String appenderName) {
        ch.qos.logback.classic.LoggerContext lc = (LoggerContext)LoggerFactory.getILoggerFactory();
        for(ch.qos.logback.classic.Logger logger : lc.getLoggerList()){
            Iterator<Appender<ILoggingEvent>> appenderIterator = logger.iteratorForAppenders();
            while(appenderIterator.hasNext()){
                Appender<ILoggingEvent> appender = appenderIterator.next();
                if (appender instanceof FileAppender){
                    FileAppender<ILoggingEvent> fileappender = (FileAppender<ILoggingEvent>)appender;
                    if (appenderName.equals(fileappender.getName())) {
                        return new File(fileappender.getFile());
                    }
                }
            }
        }
        throw new IllegalArgumentException("FileAppender not found name : "+appenderName);
    }
    @Test
    public void test1() {
        // TODO
    }
    @Test
    public void test2() {
        // TODO
    }
}