web-dev-qa-db-ja.com

Groovyスクリプトで終了ステータスを設定する方法

すべてが機能したときに_0_のstatusで終了し、さまざまなタイプの障害状態に対して_non-0 status_で終了するGroovyスクリプトがあります。たとえば、スクリプトが引数としてユーザーと電子メールアドレスを受け取った場合、無効なユーザーの場合はstatusの_1_で終了し、_2_のstatusで終了します。無効なメールアドレス形式の場合。これにはSystem.exit(statusCode)を使用します。これは正常に機能しますが、スクリプトでテストケースを作成するのが困難になります。

テストでは、GroovyShellを作成し、Bindingを作成して、Shell.run(script,args)を呼び出します。失敗条件を表明するテストの場合、System.exit()によりJVM(およびテスト)が終了します。

System.exit()を使用してGroovyスクリプトを終了する代わりの方法はありますか?キャッチされない例外をスローすることを試みましたが、出力が乱雑になり、常にステータスコードが1になります。

私たちのテストケースでは、_System.metaClass.static.invokeMethod_を使用してSystem.exit()の動作を変更し、JVMを終了しないように実験しましたが、これは醜いハックのようです。

17
Patrick

私見では System.metaClass.static.invokeMethod元気そうです。これはテストであり、ここではハッキングは問題ありません。

また、次のように、独自のラッパーを作成することもできます。

class ExitUtils {

    static boolean enabled = true

    static exit(int code) {
        if (!ExitUtils.enabled) {
            return  //TODO set some flag?
        }
        System.exit(code)
    }

}

テストのために無効にします。

10
Igor Artamonov

これが私たちが最終的に使用した手法です。

スクリプトは引き続き実行されるため、System.exit()の呼び出しを無視することはできません。代わりに、目的のステータスコードで例外をスローします。テストでSystem.exit()が呼び出されると、(カスタム)ProgramExitExceptionがスローされます

_class ProgramExitException extends RuntimeException {

    int statusCode

    public ProgramExitException(int statusCode) {
        super("Exited with " + statusCode)
        this.statusCode = statusCode
    }
}
_

次に、System.exit()をインターセプトして、この例外をスローします

_/**
 * Make System.exit throw ProgramExitException to fake exiting the VM
 */
System.metaClass.static.invokeMethod = { String name, args ->
    if (name == 'exit')
        throw new ProgramExitException(args[0])
    def validMethod =  System.metaClass.getStaticMetaMethod(name, args)
    if (validMethod != null) {
        validMethod.invoke(delegate, args)
    }
    else {
        return  System.metaClass.invokeMissingMethod(delegate, name, args)
    }
}
_

最後に、GroovyShellが任意のProgramExitExceptionをキャッチし、runメソッドからステータスコードを返します。

_/**
 * Catch ProgramExitException exceptions to mimic exit status codes
 * without exiting the VM
 */
GroovyShell.metaClass.invokeMethod = { String name, args ->
    def validMethod = GroovyShell.metaClass.getMetaMethod(name, args)
    if (validMethod != null) {
        try {
            validMethod.invoke(delegate, args)
        } catch (ProgramExitException e) {
            return e.statusCode
        }
    }
    else {
        return GroovyShell.metaClass.invokeMissingMethod(delegate, name, args)
    }
 }
_

私たちのテストはシンプルに見えるままで、スクリプトで何も変更する必要はなく、コマンドラインで実行することで期待される動作が得られます。

_assertEquals 'Unexpected status code', 0, Shell.run(script,[arg1, arg2])
assertEquals 'Unexpected status code', 10, Shell.run(script,[badarg1, badarg2])
_
5
Patrick