Hemmeligheten bak gode spesifikasjoner

Mange prosjekter har startet å ta i bruk verktøy som FitNesse eller Cucumber til å automatisere funksjonelle tester. Disse verktøyene gjør det lett å skrive akseptansetester, men det er opp til oss som bruker dem å sørge for at disse testene blir til en god spesifikasjon av systemet som skal utvikles, og ikke bare testscript. Her er noen tips for å forbedre dine spesifikasjoner.

Fokus på «hvorfor», ikke «hvordan»

Hva forsøker denne testen å uttrykke:

Når en bruker registrerer en betaling med beløp «-1234567890», så skal brukeren se en feilmelding

Hva med denne:

Når en bruker registrerer en betaling med et negativt beløp så skal brukeren få en passende feilmelding

Magiske tall, tekster og verdier i tester skjuler hva vi forsøker å spesifisere. Noen flere eksempler: «når en bruker utelater et eller flere påkrevde felter, så skal brukeren få en feilmelding knyttet til de manglende feltene», «gitt at brukeren leverer en lottorekke med for få tall».

Å koble slike tester mot systemet krever mer arbeid, spesielt de første gangene, men testene blir mye klarere etterpå. Og hovedformålet med en akseptansetest er at den er en spesifikasjon som kan diskuteres mellom prosjektet og omverdenen. Og da er det viktig å være klar. Noen ganger vil det virke svært vanskelig å automatisere forståelige spesifikasjoner. Da bør du huske at en god beskrivelse er mer verdifull enn en dårlig test.

Given-when-then

Noe av det første du lærer med tester er «bruk formen ‘gitt X, når Y, så Z'». Men det er ikke alltid så klart hva X, Y og Z skal være. Tester består av tre typer steg:

  • Arrange (oppsett, «given»): Beskriver tilstanden til systemet før testen starter. Typiske eksempler er «gitt at det eksisterer en bruker med utestående betalinger«, «gitt at tjenesten levert fra vår partner har registrert et varenummer» eller kanskje «gitt at det er en fredag» (du får vente til freddan). Avhengig av systemet og tilstanden vi beskriver, kan testen benytte disse stegene på forskjellige måter: Vi kan sette opp brukeren og betalingene i systemet, vi kan se på steget som en forutsetning som vi sjekker om er oppfylt, for eksempel ved å gjøre et søk mot tjenesten fra vår partner, vi kan forutsette, eller endog håpe at det er oppfylt og vi kan la steget kun være dokumentasjon, slik at når testen feiler, så vet vi noen ting vi kan verifisere manuelt, eller det kan være en ren løgn. Kanskje systemet er satt opp på en spesiell måte slik at det ikke er avhengig av ukedagen. Men vi har lyst til å dokumentere hvordan det hadde sett ut om det hadde vært «på ordentlig.»
  • Act (utfør, «when»): Beskriver stimuli inn fra omverden. «Når brukeren registrerer en ny betaling,» «når klientsystemet sender en betalingsforespørsel med manglende kundeinformasjon». Disse kan implementeres på flere måter i de fleste systemer: Et test av et web-grensesnitt kan simulere en klient med for eksempel webdriver, den kan gjøre et http-kall og direkte, eller testen kan bruke klassene som implementerer tjenesten direkte. For funksjonelle tester foretrekker jeg nesten alltid det siste. Det gjør at testene vil kjøre hundre ganger raskere, og vil som regel innebære mindre jobb. Husk: Det er ikke nødvendig å teste brukergrensesnittet på nytt for hver valideringsregel eller spesialtilfelle i applikasjonen din.
  • Assert (sjekk, «then»): Beskriver hvordan systemet skal reagere på stimuli og hva tilstanden til systemet skal være etterpå. For eksempel «så skal brukeren få en feilmelding om at alle betalinger må være utført før en ny betaling kan registreres», «så skal den nye betalingen ikke lagres i systemet.»

Veien fra testscript til spesifikasjoner

Når prosjekter først tar i bruk FitNesse er det veldig vanlig å se tester som ser cirka slik ut:

  • Putt inn en kjempeliste med rader med en bråte kolonner inn i tabell A.
  • Putt inn en ny kjempelist med rader etc i tabell B
  • Send inn et kjempemessig XML dokument
  • Sjekk at svaret matcher et nytt XML dokument

Dette er ikke en spesifikasjon – det er et testscript. Og det er ikke slike tester som gir verdi til et prosjekt. Men det er et sted å starte, for det krever ikke så veldig mye kreativitet. Og vi kan gjenbruke lærdommen fra slike tester. Men før det blir en hel skog av tester som dytter XML-dokumenter hit og dit, kan det være lurt å løfte testene opp på et mer logisk nivå:

  • Gitt at det ikke eksisterer noen betalingsforespørsler
  • Og en bruker er registrert
  • Når brukeren sender inn en betalingsforespørsel med ett gitt problem
  • Så skal brukeren få feilmeldingen en gitt feilmelding

I FitNesse-terminologi kan en slik test implementeres som en ColumnFixture. Det vil si: Hvert par av «problem» og «feilmelding» er en rad i en tabell. Slik kan vi uttrykke mange regler ved systemet klart og konsist.

Dersom du har startet å gå veien med testscript, er det ikke vanskelig å snu: For hver rad i den nye spesifikasjonen din skal du utføre alt det testscriptet ditt gjorde.

Jeg vil bruke jobben med akseptansetester til ikke bare å gjøre automatiske kjøringer av systemet mitt, men til å spesifisere og diskutere de egentlige kravene brukerne mine bryr seg om. Og dersom jeg må velge mellom tester som lar seg automatisere og spesifikasjoner som beskriver kravet, vil jeg alltid velge det siste.

En kommentar om “Hemmeligheten bak gode spesifikasjoner”

Legg igjen en kommentar