Dominik Moštěk
18.10.2013

Testování v Groovy



Na našem prvním Radaru jsme se rozhodli nasadit Groovy jakožto jazyk pro psaní unit testů. Jaké s tím máme zkušenosti po roce používání jsem shrnul v tomto článku.

Proč Groovy?

  • Protože je kompatibilní s Javou a průměrný Java programátor s ním během chvilky umí. I když všechna zákoutí Groovy objevujeme ještě dnes, naučení je opravdu rychlé.
  • Groovy šetří. Testy místo Java boilerplate obsahují skutečný popis testovaného chování.
  • Pro jednoduché mockování dokáže nahradit mockovací framework.

 

Proč jen na testy?

 

Podpora v IDE a Maven

IntelliJ IDEA funguje out of the box bez komplikací. Plugin pro Eclipse existuje, někdy je mírně komplikovanější ho zprovoznit, ale jde to. Pro Netbeans existuje také plugin, který funguje bez komplikací.

Vše co je potřeba v Maven nastavit je jeden plugin.

<plugin>
  <groupId>org.codehaus.gmaven</groupId>
  <artifactId>gmaven-plugin</artifactId>
  <version>1.4</version>
  <configuration>
    <providerSelection>2.0</providerSelection>
    <sourceEncoding>UTF-8</sourceEncoding>
  </configuration>
  <executions>
    <execution>
      <goals>
        <goal>testCompile</goal>
      </goals>
      <configuration>
        <sources>
          <fileset>
            <directory>${pom.basedir}/src/test/java</directory>
            <includes>
              <include>**/*.groovy</include>
            </includes>
          </fileset>
        </sources>
      </configuration>
    </execution>
  </executions>
</plugin>

 

Příklady

Zde je pár příkladů, které dělají testování pomocí Groovy příjemnější:

Inicializace objektů

Objekty lze inicializovat jmenováním jejich parametrů v konstruktoru.
def person = new Person(name: "Joe", age: 23, address: new Address(street: "Sesame", zipCode: 12345))
Což je řádově méně, než postupná inicializace settery.

Název metody jako String

To nám umožňuje popsat testovací případ názvem metody.

def "date have to be in MM/dd/yyyy format" () {
  ... 
}

 

Není potřeba setteru pro závislosti

Jelikož private atributy tříd nejsou v Groovy (momentálně) skutečně privátní, nemusí mít naše objekty settery pro závislosti, které jsou jinak doplněny IoC kontejnerem přes reflexi.

Podpora Closure

To usnadňuje práci asi ze všeho nejvíc. Příkladem může být tato metoda, která vykoná předaný closure v separátní transakci v rámci integračního testu:

void executeInSeparateTransaction(def closure) {
  new TransactionTemplate(transactionManager).execute(new TransactionCallbackWithoutResult() {
    protected void doInTransactionWithoutResult(TransactionStatus status) {
      closure() 
    }
  })
}

 

Takže test může vypadat následovně:

executeInSeparateTransaction({ userService.logRecentIntegration(one.id, user.id) }) executeInSeparateTransaction({ userService.logRecentIntegration(two.id, user.id) })

 

Práce s datem a časem

Groovy poskytuje příjemné API a DSL pro práci s datem a časem.

def now = Calendar.instance.time use(TimeCategory) { def twoMothsAgo = now - 2.month }

 

Override metod v runtime

MetaClass v Groovy je zdrojem mnoha překvapení a šikovných vlastností. Jednou z nich je, že můžeme za běhu přidávat objektu metody, přepisovat mu je, či dokonce vytvořit catch-metodu. Příkladem může být tento kód, který přepíše všechna statická volání na enum:

Action.metaClass.'static'.invokeMethod = { String name, args -> "andThisIsAction".equals(args) ? Action.EDIT : null } 

 Ale i toto má ještě své mouchy.

Mocky

Pokud nepotřebujeme složité mocky, nebudeme potřebovat ani žádný framework. Řekněme, že naše servisní třída potřebuje mock dao objektu:

def service = new Service(); service.userDao = [ findUser : { String username -> new DummyUser(username) } ] as UserDao

 

Zkratky

Některé běžné věci jako cykly se dají v Groovy zapsat velice jednoduše:

result.each { master -> assertThat(master.service, is(service)) } 

 

Slabé stránky

Refaktoring Java kódu nezasáhne Groovy ve všech případech. Vyplývá to z toho, že Groovy je dynamický jazyk a proto IDE neví, kde všude je potřeba refaktorovat.

V Groovy lze zapsat všechno mnoha různými způsoby, což je určitě příjemné, ale ne když na jednom projektu pracuje několik programátorů, z nichž každý si oblíbil jiný styl.

Zhodnocení

Groovy mě donutil začít praktikovat TDD na 100 %. Předtím jsem psaní testů bral spíš jako nutné zlo, protože ukecanost Javy testy kolikrát proměnila v příšerné hromady kódu. S Groovy mě psaní testů baví.

Vaše emailová adresa nebude zveřejněna

Komentáře

Děkujeme za váš komentář
Další
  • Je skvělé vidět, jak Groovy pomalu proniká i do českých firem. Měl bych jenom pár doporučení. Pokud již chcete testovat v Groovy, je lepší použít Spock Framework, který testování posouvá na úplně jiný level. K vývojovým prostředím: Obecně nejpoužívanější je IntelliJ. Na bázi Eclipse je oficiální distribuce Groovy Grails Tool Suite přímo od Pivotalu, který nyní zastřešuje Groovy a Grails. Pokud vím, dá se to nainstalovat jako samostatná distribuce i jako features z update site. NetBeans bohužel hodně ujel vlak a přilíš použitelné stále nejsou, i když se v poslední době snaží hodně dohánět zbylé dva. Styl programování můžete částečně vynutit používáním CodeNarc, který je obdobou PMD či FindBugs pro Javu.

  • Dominik Moštěk

    Děkuji za komentář i odkazy. Ja osobně s Tool suite pro eclipse nemám dobré zkušenosti, i když po strastiplném zprovoznění fungoval už bez problémů. Také musím pochválit váš blog.

  • Anonym

    Díky. Souhlasím s tím, že zprovoznit Eclipse tak, aby fungoval je docela fuška. Proto jsem rád, že nabízejí přímo bundle pro Groovy a Grails, kde vše funguje téměř bez problému. Já Eclipse pro Groovy upřednostňuji hlavně kvůli tomu, že se do něj poměrně snadno přidávají deskriptory pro DSL, takže napovídá i tam, kde to obecně nelze. IntelliJ má něco podobného, jenom se tam víc musí spoléhat na to JetBrains, pokud se nedaří vytvořit správný pointcut.