技術関連の覚書

案件でやったり自宅で試したことの覚書

Javaでテストするときの話

私は仕事でJavaを使うことが多いのですが、大抵裏方の方で画面まわりよりもバッチなどの方が多い。 そのため、テスト自体はInputとOutputが明確な事が多くて割合テストがしやすい事が多いのですが、バッチの作り方故に問題に上がるものも多いのでそれを書いておきます。

System.exit()で終了する作りにするとテストが継続できなくなる

System.exitはそのままだとJVM自体終了するので自動テストの場合続行できなくなります。

対処法

SecurityManagerクラスをOverrideしてcheckExitメソッドの動きを変える。

方法はこちらを参照したと記憶しています。 JUnit System.exit するメソッドをテストする - Qiita

例 Exit1.java

/**
 * @author M.H
 *
 */
public class Exit1 {
   public static void f() {
      System.exit(0);
   }
}

Exit2.java

/**
 * @author masataka
 *
 */
public class Exit2 {
    public static void f() {
        System.out.println("reached");
    }
}

テストクラス

import org.testng.annotations.Test;

import jp.boctok.sample8.exit.Exit1;
import jp.boctok.sample8.exit.Exit2;

import org.testng.annotations.BeforeMethod;

import static org.junit.Assert.assertTrue;

import java.security.Permission;

import org.testng.annotations.AfterMethod;

/**
 * テストクラス
 * @author M.H
 *
 */
public class NewTest {
    /**
     * SecurityExceptionを継承した独自Exception
     * @author M.H
     *
     */
    class ExitException extends SecurityException {
        /** serialVersionUID フィールド説明 */
        private static final long serialVersionUID = 1L;
        public int s = 1;
        
        public ExitException(int s) {
            this.s = s;
        }
    }

    /**
     * テストメソッド
     */
    @Test
    public void f() {
        try {
            Exit1.f();
        }catch(ExitException e) {
            assertTrue(true);
        }
        Exit2.f();
        assertTrue(true);
    }

    /**
     * テストメソッド実施前に実行
     */
    @BeforeMethod
    public void beforeMethod() {
        SecurityManager sm = new SecurityManager() {
            // こちらは特に何もしない
            // とは言ってもcheckExitから呼ばれてますが
            public void checkPermission(Permission p) {
                
            }
            
            @Override // このメソッドをいじる
            public void checkExit(int s) {
                throw new ExitException(s);
            }
        };
        System.setSecurityManager(sm);
    }
}

System.exit()メソッドの中は

    public void exit(int status) {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkExit(status);
        }
        Shutdown.exit(status); //<--ここでJVMを終了させています
    }

といった感じです

System.out.printlnで出力された文字列のAssertEquals

こちらはPrintStreamオブジェクトにByteArrayOutputStreamのインスタンスを渡してあげる方法になります。 この方法は、JVMが動作している間その挙動になるため、テスト後に処理を戻す必要があります。

この続きは明日書きます。