Как установить статус выхода в скрипте Groovy

У нас есть сценарий 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, но это похоже на уродливый хак.


person Patrick    schedule 16.02.2012    source источник


Ответы (2)


имхо 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)
    }

}

и отключите его для тестов.

person Igor Artamonov    schedule 17.02.2012
comment
Спасибо. Я подчистил нашу System.metaClass.static.invokeMethod работу, и она выглядела намного менее хакерской. - person Patrick; 18.02.2012
comment
Просто предупреждение для тех, кто попытается сделать это на этапе скрипта конвейера Jenkins, это уничтожит весь процесс Jenkins. - person jxramos; 15.12.2018

Вот техника, которую мы в итоге использовали.

Мы не можем просто игнорировать вызов 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])
person Patrick    schedule 18.02.2012