Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

バッチ処理などで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));
        }
    }
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした