1. ホーム

[解決済み】Javaです。System.exit()を呼び出すメソッドをテストするにはどうすればよいですか?

2022-04-07 10:31:45

質問

を呼び出すべきいくつかのメソッドがあります。 System.exit() を特定の入力で使用します。残念ながら、これらのケースをテストすると、JUnit が終了してしまうのです! メソッド呼び出しを新しいスレッドに置いても、次のような理由で解決しないようです。 System.exit() は、現在のスレッドだけでなく、JVMを終了させます。これに対処するための一般的なパターンがありますか?例えば、私は、スタブの代わりに System.exit() ?

[EDIT] 問題のクラスは、実はコマンドラインツールで、JUnitの中でテストしようとしているのです。もしかしたら、JUnitはこの仕事に適したツールではないかもしれませんね?補完的なリグレッションテストツールの提案を歓迎します(できればJUnitとEclEmmaとうまく統合するものです)。

解決方法は?

確かに。 Derkeiler.com を提案します。

  • なぜ System.exit() ?

System.exit(whateverValue) で終了させる代わりに、チェックされていない例外を投げてはどうでしょうか?通常の使用では、それはJVMの最後の捨て身のキャッチャーまでずっと漂い、スクリプトをシャットダウンします(途中でそれをキャッチすることを決定しない限り、それはいつか役に立つかもしれません)。

JUnitのシナリオでは、これはJUnitフレームワークによって捕捉され、JUnitフレームワークが次のように報告します。 このようなテストは失敗し、次のテストにスムーズに進みます。

  • 防止する System.exit() を使用して実際にJVMを終了させます。

System.exit を呼び出さないようにするセキュリティ・マネージャで実行するようにテストケースを修正し、SecurityException をキャッチしてみてください。

public class NoExitTestCase extends TestCase 
{

    protected static class ExitException extends SecurityException 
    {
        public final int status;
        public ExitException(int status) 
        {
            super("There is no escape!");
            this.status = status;
        }
    }

    private static class NoExitSecurityManager extends SecurityManager 
    {
        @Override
        public void checkPermission(Permission perm) 
        {
            // allow anything.
        }
        @Override
        public void checkPermission(Permission perm, Object context) 
        {
            // allow anything.
        }
        @Override
        public void checkExit(int status) 
        {
            super.checkExit(status);
            throw new ExitException(status);
        }
    }

    @Override
    protected void setUp() throws Exception 
    {
        super.setUp();
        System.setSecurityManager(new NoExitSecurityManager());
    }

    @Override
    protected void tearDown() throws Exception 
    {
        System.setSecurityManager(null); // or save and restore original
        super.tearDown();
    }

    public void testNoExit() throws Exception 
    {
        System.out.println("Printing works");
    }

    public void testExit() throws Exception 
    {
        try 
        {
            System.exit(42);
        } catch (ExitException e) 
        {
            assertEquals("Exit status", 42, e.status);
        }
    }
}


2012年12月更新

ウィル プロポーズ コメントで を使って システムルール を使用するコードをテストするためのJUnit(4.9+)のルールのコレクションです。 java.lang.System .

このことは、当初 ステファン・ビルクナー 回答 2011年12月に発表しました。

System.exit(…)

を使用します。 ExpectedSystemExit ルールで確認することができます。 System.exit(…) が呼び出されます。

終了時の状態も確認できますね。

例えば

public void MyTest {
    @Rule
    public final ExpectedSystemExit exit = ExpectedSystemExit.none();

    @Test
    public void noSystemExit() {
        //passes
    }

    @Test
    public void systemExitWithArbitraryStatusCode() {
        exit.expectSystemExit();
        System.exit(0);
    }

    @Test
    public void systemExitWithSelectedStatusCode0() {
        exit.expectSystemExitWithStatus(0);
        System.exit(0);
    }
}