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

У нас есть Groovy Script, который выходит с status из 0 когда все работало и non-0 status для разных типов условий отказа. Например, если скрипт взял в качестве аргументов пользователя и адрес электронной почты, он завершился бы с status из 1 для недопустимого пользователя и status из 2 для неверного формата адреса электронной почты. Мы используем System.exit(statusCode) за это. Это прекрасно работает, но делает сценарий трудным для написания тестовых случаев.

В тесте мы создаем наш GroovyShell, создайте наш Binding и позвонить shell.run(script,args), Для тестов, которые утверждают условия отказа, System.exit() заставляет JVM (и тест) выйти.

Есть ли альтернативы использованию System.exit() выйти из Groovy Script? Я экспериментировал с генерацией необработанных исключений, но это загромождает вывод и всегда делает код состояния 1.

В наших тестах я также экспериментировал с использованием System.metaClass.static.invokeMethod изменить поведение System.exit() не выходить из JVM, но это похоже на уродливый хак.

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

}

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

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

Мы не можем просто игнорировать звонок 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])
Другие вопросы по тегам