如何在Groovy脚本中设置退出状态

Pat*_*ick 17 groovy unit-testing exit-code

我们有一个Groovy脚本与一个退出status0时候一切工作和non-0 status针对不同类型的故障条件.例如,如果脚本了用户和一个电子邮件地址作为参数,它将与一个退出status1为无效的用户,和status2为无效的电子邮件地址格式.我们用System.exit(statusCode)它.这工作正常,但使脚本难以编写测试用例.

在测试中,我们创建我们的GroovyShell,创建我们的Binding和调用shell.run(script,args).对于断言失败条件的测试,System.exit()导致JVM(和测试)退出.

是否有使用System.exit()退出Groovy脚本的替代方法?我尝试抛出未捕获的异常,但是使输出变得混乱,并且始终使状态代码为1.

在我们的测试用例中,我还尝试使用System.metaClass.static.invokeMethod更改System.exit()不退出JVM 的行为,但这似乎是一个丑陋的黑客.

Igo*_*nov 10

imho 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)
    }

}
Run Code Online (Sandbox Code Playgroud)

并禁用它进行测试.


Pat*_*ick 5

这是我们最终使用的技术.

我们不能忽略调用,System.exit()因为脚本将继续运行.相反,我们想要使用所需的状态代码抛出异常.我们在测试中调用ProgramExitException时抛出(自定义)System.exit()

class ProgramExitException extends RuntimeException {

    int statusCode

    public ProgramExitException(int statusCode) {
        super("Exited with " + statusCode)
        this.statusCode = statusCode
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我们拦截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)
    }
}
Run Code Online (Sandbox Code Playgroud)

最后我们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)
    }
 }
Run Code Online (Sandbox Code Playgroud)

我们的测试看起来很简单,我们不需要更改脚本中的任何内容,我们可以获得在命令行上运行的预期行为.

assertEquals 'Unexpected status code', 0, shell.run(script,[arg1, arg2])
assertEquals 'Unexpected status code', 10, shell.run(script,[badarg1, badarg2])
Run Code Online (Sandbox Code Playgroud)