Вот техника, которую мы в конечном итоге использовали.
Мы не можем просто игнорировать вызов System.exit()
, так как скрипт продолжит работать. Вместо этого мы хотим вызвать исключение с желаемым кодом состояния. Мы бросаем (custom) 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])