Как установить статус выхода в Groovy Script
У нас есть Groovy Script, который завершает работу с status
of 0
, когда все работает, и non-0 status
для разных типов сбоев. Например, если Script взял пользователя и адрес электронной почты в качестве аргументов, он выйдет с status
из 1
для недопустимого пользователя и status
из 2
для недопустимого формата адреса электронной почты. Для этого мы используем System.exit(statusCode)
. Это прекрасно работает, но затрудняет запись Script тестовых примеров.
В тесте мы создаем наш GroovyShell
, создаем наш Binding
и вызываем shell.run(script,args)
. Для тестов, которые утверждают условия отказа, System.exit()
приводит к выходу JVM (и теста).
Существуют ли альтернативы использованию System.exit()
для выхода из Groovy Script? Я экспериментировал с бросанием неперехваченных исключений, но это загромождает вывод и всегда делает код состояния 1.
В наших тестовых случаях я также экспериментировал с использованием System.metaClass.static.invokeMethod
, чтобы изменить поведение System.exit()
, чтобы не выходить из JVM, но это кажется уродливым взломом.
Ответы
Ответ 1
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)
}
}
и отключите его для тестов.
Ответ 2
Вот техника, которую мы в конечном итоге использовали.
Мы не можем просто игнорировать вызов System.exit()
, так как script будет продолжать работать. Вместо этого мы хотим выдать исключение с желаемым кодом состояния. Мы бросаем (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])