JUnit Rules (tenk composition over inheritance for tester)

JUnit Rules (tenk composition over inheritance for tester)

Overskriften refererer til det alt for lite brukte @Rule JUnit APIet som lar en samle felles testfunksjonalitet uten å innføre unødvendige komplekse klassehierarkier i testkoden. Kort fortalt er det composition over inheritance for JUnit tester.

Hva har JUnit og @Rule med dette å gjøre?

Når en skriver tester, og spesielt tester som begir seg inn på "integrasjonstest territoriet" ender man veldig fort med behov for å styre livssyklusen til en del tjenester og ressurser. Noen tester trenger en in-memory database, noen en meldingskø, mens andre trenger tilgang til et reelt filsystem og på et eller annet tidspunkt får noen tester behov for alle tre. Dersom en implementerer dette med arv ender en opp med en enorm akstrakt baseklasse for disse testene som kjenner til alt fra start og stopp av meldingskøer til databaser og er så langt fra single responsibility principle som det er mulig å komme. Siden JUnit 4.7 som ble sluppet i juni 2009 har man hatt et langt bedre alternativ til dette, men som fortsatt er relativt lite brukt.

Eksempel på start og stopp av in-memory databaseserver

  1. Oppretter en ny in-memory database med støtte for flere tilkoblinger.
  2. Obs, H2 vil (dersom en ikke setter DB_CLOSE_DELAY = -1) slette in-memory databasen når den siste tilkoblingen lukkes. Derfor åpner vi en tilkobling som lukkes etter at testen har kjørt ferdig. Dette kan være et frustrerende problem å debugge blant annet fordi connection pools vil maskere problemet.
  3. Et egnet sted for convenience metoder for.. kjøring av spørringer, dumping av database og andre operasjoner som kan være nyttig under testing og debugging.

Enkelt eksempel

  1. Initier regelen, her sender vi inn navnet på databasen vi ønsker
  2. Gjør noe fornuftig med tilkoblingen

Noen kommentarer til implementasjonen

Det er mange måter å implementere @Rule på, men ExternalResource som demonstrert ovenfor dekker det veldig typiske "jeg trenger å kjøre noe kode før og etter hver test" behovet som melder seg hver gang en trenger å starte en server, allokere ressurser før testen og rydde opp etterpå. Dersom en trenger mer fleksibilitet kan man implementere grensesnittet TestRule.

Mer informasjon

For mer informasjon anbefaler jeg rett og slett å ta en titt på kildekoden til de implementasjonene som følger med JUnit. Det finnes også noe informasjon på wiki siden på Github.


Ideer

Her er en langt fra uttømmende liste over ting jeg med hell har brukt dette APIet til:

  1. Tilgang til midlertidige filer og mapper på filsystemet
  2. Instrumentering (ta tiden på alle tester)
  3. Kjøre et bestemt sub-set av tester basert på forskjellige kriterier
  4. Start / stopp av:
    a. In-memory meldingskøer
    b. Andre typer servere for testing (http, ftp, osv)
    c. Docker containere (spennende!)

comments powered by Disqus