我们有一个Groovy脚本,当一切正常时,status
0
退出,而non-0 status
针对不同类型的失败条件退出。例如,如果脚本将用户和电子邮件地址作为参数,则对于无效用户,status
1
将退出,而status
为2
邮件地址格式无效。我们使用System.exit(statusCode)
。这样可以正常工作,但是使脚本难以编写测试用例。
在测试中,我们创建了GroovyShell
,创建了我们的Binding
并致电shell.run(script,args)
。对于断言失败条件的测试,System.exit()
会导致JVM(和测试)退出。
是否有使用System.exit()
退出Groovy脚本的替代方法?我尝试了抛出未捕获的异常,但这会使输出变得混乱,并且总是生成状态代码1.
在我们的测试用例中,我还尝试使用System.metaClass.static.invokeMethod
来改变System.exit()
的行为以不退出JVM,但这看起来像是一个丑陋的黑客。
答案 0 :(得分: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)
}
}
并禁用它进行测试。
答案 1 :(得分:5)
这是我们最终使用的技术。
我们不能忽略对System.exit()
的调用,因为脚本会继续运行。相反,我们想要使用所需的状态代码抛出异常。我们在测试中调用ProgramExitException
时抛出(自定义)System.exit()
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])