2012-02-16 8 views
15

Mamy Groovy Script, który kończy się status z 0, gdy wszystko działało i non-0 status dla różnych rodzajów warunków awarii. Na przykład, jeśli skrypt wziął użytkownika i adres e-mail jako argumenty, zakończyłby się status z 1 dla nieprawidłowego użytkownika i status z 2 dla nieprawidłowego formatu adresu e-mail. Używamy do tego System.exit(statusCode). Działa to dobrze, ale sprawia, że ​​skrypt jest trudny do napisania przypadków testowych.Jak ustawić status wyjścia w Groovy Script

Podczas testu tworzymy naszą GroovyShell, tworzymy naszą Binding i dzwonimy pod numer shell.run(script,args). W przypadku testów potwierdzających warunki niepowodzenia, System.exit() powoduje wyjście JVM (i testu).

Czy istnieją alternatywy dla używania System.exit() do zamykania skryptu Groovy? I eksperymentowali z rzucania niezłapane wyjątki, ale to zaśmiecanie wydajność i zawsze sprawia, że ​​kod statusu 1.

W naszych testach Mam również eksperymenty z użyciem System.metaClass.static.invokeMethod aby zmienić zachowanie System.exit() aby nie wyjść z JVM, ale wydaje się, że jak brzydki hack.

Odpowiedz

9

imho System.metaClass.static.invokeMethod wygląda dobrze. To jest test, a hakowanie jest tutaj w porządku.

Ponadto można tworzyć własne otoki wokół niego, jak:

class ExitUtils { 

    static boolean enabled = true 

    static exit(int code) { 
     if (!ExitUtils.enabled) { 
      return //TODO set some flag? 
     } 
     System.exit(code) 
    } 

} 

i wyłączyć go do testów.

+0

Dzięki. Oczyściłem naszą pracę 'System.metaClass.static.invokeMethod' i wyglądało to o wiele mniej hacky. – Patrick

4

Oto technika, którą ostatecznie wykorzystaliśmy.

Nie możemy po prostu zignorować połączenia z numerem System.exit(), ponieważ skrypt będzie nadal działał. Zamiast tego chcemy rzucić wyjątek z żądanym kodem statusu. Rzucamy (niestandardowe) ProgramExitException gdy System.exit() nazywa się w naszych testach

class ProgramExitException extends RuntimeException { 

    int statusCode 

    public ProgramExitException(int statusCode) { 
     super("Exited with " + statusCode) 
     this.statusCode = statusCode 
    } 
} 

wtedy przechwycić System.exit() rzucić wyjątek ten

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

i wreszcie mamy GroovyShell złapać jakikolwiek ProgramExitException i zwrócenia kodu stanu z metoda 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) 
    } 
} 

Nasze testy mogą zatrzymać patrząc proste, nie musimy nic zmieniać w skryptach i otrzymujemy zachowania oczekujemy od uruchomiony w wierszu poleceń.

assertEquals 'Unexpected status code', 0, shell.run(script,[arg1, arg2]) 
assertEquals 'Unexpected status code', 10, shell.run(script,[badarg1, badarg2])