LoginSignup
7
9

More than 5 years have passed since last update.

Java System.exit()処理を無効にして代わりにExceptionを発生させる。

Last updated at Posted at 2015-10-21

バッチ処理などで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));
        }
    }
}
7
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
9