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

Unit testing 如何在Groovy脚本中设置退出状态,unit-testing,groovy,exit-code,Unit Testing,Groovy,Exit Code,我们有一个Groovy脚本,当一切正常时,它的状态为0,对于不同类型的故障条件,它的状态为非0。例如,如果脚本将用户和电子邮件地址作为参数,则对于无效用户,脚本将以状态退出,对于无效电子邮件地址格式,脚本将以状态退出。为此,我们使用System.exit(statusCode)。这可以很好地工作,但会使脚本编写测试用例变得困难 在测试中,我们创建GroovyShell,创建绑定,并调用shell.run(脚本,args)。对于断言失败条件的测试,System.exit()会导致JVM(和测试)退

我们有一个Groovy脚本,当一切正常时,它的
状态为
0
,对于不同类型的故障条件,它的状态为
非0
。例如,如果脚本将用户和电子邮件地址作为参数,则对于无效用户,脚本将以
状态
退出,对于无效电子邮件地址格式,脚本将以
状态
退出。为此,我们使用
System.exit(statusCode)
。这可以很好地工作,但会使脚本编写测试用例变得困难

在测试中,我们创建
GroovyShell
,创建
绑定
,并调用
shell.run(脚本,args)
。对于断言失败条件的测试,
System.exit()
会导致JVM(和测试)退出

除了使用
System.exit()
退出Groovy脚本,还有其他方法吗?我尝试抛出未捕获的异常,但这会使输出变得混乱,并且总是使状态代码为1


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

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

}

并禁用它进行测试。

这是我们最终使用的技术

我们不能忽略对
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])

谢谢我清理了我们的
System.metaClass.static.invokeMethod
工作,它看起来没有那么黑客。这只是对在Jenkins管道groovy脚本步骤中尝试这样做的其他人的一个警告,这将杀死整个Jenkins进程。