バッチ処理などでSystem.exit()で終わる処理をJUnitでテストするとJVMが終了してしまう。
exit()処理の代わりにExceptionを発生させ、テストを可能にするためのクラス。
基本的にはSystem.exit()など使わずにreturnを使うんだが、古いバッチをメンテナンスするとよくある。
SystemExitStub.java
package testlib.system;
import java.security.Permission;
/**
* System.exit()処理を無効にし代わりにExitExceptionを発生させる.<br>
* JUnitでSystem.exitのある処理をテストを実施する場合等に使用する。<br>
* 本クラスはスレッドセーフではないのでマルチスレッド環境では利用不可。<br>
* シングルトンクラス。
*
* @author boss_ape
*/
public final class SystemExitStub extends SecurityManager
{
/** シングルトンパターンのためのインスタンス. */
private static final SystemExitStub INSTANCE_STUB = new SystemExitStub();
/** 現在使われている変更前のセキュリティマネージャ. */
private static final SecurityManager INSTANCE_SYSTEM = System.getSecurityManager();
/**
* デフォルトコンストラクタの禁止.
*/
private SystemExitStub() { }
/**
* このクラスのインスタンスを取得.
*
* @return このクラスのインスタンス
*/
public static SystemExitStub getlnstance()
{
return INSTANCE_STUB;
}
@Override
public void checkPermission(Permission permission)
{
if ("exitVM".equals(permission.getName()))
System.out.println("System.exit[exitVM]が呼ばれた");
}
@Override
public void checkExit(int status)
{
throw new ExitException(status);
}
/**
* System.exit()をExitExceptionに変更設定する.
*/
public void change()
{
// JVMを終了させない
System.setSecurityManager(INSTANCE_STUB);
}
/**
* System.exit()を元に戻す.
*/
public void reset()
{
System.setSecurityManager(INSTANCE_SYSTEM);
}
/**
* JVMの停止の代わりに発生させるException.
*
* @author boss_ape
*/
public class ExitException extends SecurityException
{
public int state = 0;
public ExitException(int state)
{
this.state = state;
}
}
}
以下、使用サンプル。
Javaバッチとそのテスト。
まずはJavaバッチサンプル
SampleBatch.java
package jp.co.ivynetwork.batch;
/**
* FugaFugaをFugeFugeするバッチ処理.<br>
* 0:正常終了<br>
* 1:異常終了
*
* @author boss_ape
*/
public class SampleBatch
{
public static void main(String[] args)
{
try {
// パラメータが何か指定されていたらException発生
if (null == args)
throw new NullPointerException();
} catch (NullPointerException e) {
System.exit(1);
}
System.exit(0);
}
}
上記バッチのJUnitテスト
SampleBatchTest.java
package jp.co.ivynetwork.batch;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import testlib.system.SystemExitStub;
/**
* バッチテスト.<br>
* テスト実行中、System.exit()でJVMが終了しないようにExitExceptionをスローする。
*
* @author boss_ape
*/
public class SampleBatchTest
{
/** System.exit変更管理オブジェクト. */
private SystemExitStub exit = SystemExitStub.getlnstance();
/**
* テストメソッド実行前にSystem.exit()設定を変更.
*/
@Before
public void changeSystem()
{
// System.exit()をExitExceptionに変更
exit.change();
}
/**
* テストメソッド実行後にSystem.exit()設定を戻す.
*/
@After
public void resetSystem()
{
// System.exit()設定を元に戻す
exit.reset();
}
/**
* main処理のテスト.<br>
* パラメータnullで実行時、exit(1)で終了する事を確認
*/
@Test
public void testMainパラメータにnullを設定()
{
try {
// バッチ実行
SampleBatch.main(null);
// 通常のSystem.exit()が実行された場合、JUnitのランナーそのものが終了してしまう
} catch (SystemExitStub.ExitException e) {
// System.exit(1)で終了していたら正常
assertThat(e.state, is(1));
}
}
/**
* main処理のテスト.<br>
* パラメータ指定で実行時、exit(0)で終了する事を確認
*/
@Test
public void testMainパラメータに値を設定()
{
try {
// バッチ実行
SampleBatch.main(new String[] { "パラメータ指定" });
// 通常のSystem.exit()が実行された場合、JUnitのランナーそのものが終了してしまう
} catch (SystemExitStub.ExitException e) {
// System.exit(0)で終了していたら正常
assertThat(e.state, is(0));
}
}
}