すべてが機能したときに_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を終了しないように実験しましたが、これは醜いハックのようです。
私見では 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)
}
}
テストのために無効にします。
これが私たちが最終的に使用した手法です。
スクリプトは引き続き実行されるため、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])
_