Arkiv

Idlæg Tagged ‘tdd’

Test-Driven Development – hvad, hvordan og hvorfor?

28 april, 2009 dinbror 12 kommentarer

Motivation

Efter at have afleveret hovedopgave på datamatikeruddannelsen, som blev lavet sammen med to medstuderende, skulle jeg forberede et 10 minutters oplæg.  Her lå mit interesseområde indenfor optimering. Hvordan kunne vi have gjort vores proces og produkt bedre?
Igennem undervisning var vi blevet introduceret til udviklingsmetoden eXtreme Programming [1]. Vi brugte en del af metodens arbejdspraksisser dog ikke Test-first programmering, selvom det havde været ideen fra starten af. Den manglende erfaring samt manglende viden omkring emnet havde skræmt os, og da vi havde anvendt en del ny teknologi i form af Adobe Flex, Hibernate, BlazeDS mm. var den blevet nedprioteret, hvorfor en fordybelse i emnet forekom naturligt.

Hvad er Test-Driven Development?

Test-driven development, herefter forkortet TDD, har været anvendt i årtier. Den er blevet en del af eXtreme Programmings arbejdspraksisser i form af test-first programmering. Det er her jeg er blevet gjort bekendt med teknikken. Det er en softwareudviklingsteknik, og ikke blot en test metode, som mange måske tror! Det er en teknik til at programmere med og fastligge krav til sit software. I eXtreme Programming er den med til at understøtte udvikleren med øjeblikkelig feedback på sit arbejde.

Hvordan bruges Test-Driven Development?

Nedestående figur illustrerer TDDs anvendelse. Jeg har delt det op i 6 trin:

Hvordan bruges test-driven development?

Hvordan bruges Test-Driven Development?

  1. Tilføj en test: Man starter med at lave sin test. Testkoden laves før selve programkoden, hvorfor udvikleren tvinges til at tænke over kravene inden der udvikles. Dette er den største forskel kontra almindelige unit test.
  2. Kør alle tests: Herefter køres testen. Vi forventer at den fejler, da programkoden ikke er udviklet endnu, men skulle den mod forventning bestå, går man tilbage til trin 1, da testen tydeligvis ikke virker.
  3. Skriv noget kode: Nu udvikles programkoden. Her er det vigtigt, at man ikke begynder at forudse problemer, men kun fokuserer på at testen skal lykkes.
    Kent Beck, skaberen af eXtreme Programming, skriver om flere strategier for, hvordan man hurtigst muligt få sine tests til at bestå. Bl.a. kommer han med udtalelsen: “Fake it (till you make it)”, som går på at man starter med at returner en konstant, og først senere laver den om til en variabel i den endelige kode.
  4. Kør alle tests: Herefter køres testen igen. Igen er der to mulige output. Fejler testen går man tilbage til trin 3 og kigger sin programkode igennem. Består testen går man videre til trin 5.
  5. Refactor: Test- og program-koden gennemses og eventuelt optimeres. Hvis der er duplikater i form af fx temp værdier og strings fjernes disse. Det er vigtigt at dubleret kode fjernes, da det medvirker til et dårligere design, inkonsistens og mindre tillid til koden, især når udvikleren glemmer, hvor det dublerede kode er.
  6. Kør alle tests: Testen køres igen. Fejler den vender man tilbage til trin 5, ellers fortsætter man med næste krav og trin 1. Det er vigtigt at man hele tiden får kørt sine test, så en eventuel fejl ikke når at blive stor og ressourcekrævende.

Hvorfor bruge Test-Driven Development?

Ja, hvorfor skal man bruge Test-Driven Development? Herunder har jeg opridset nogle klare fordele ved TDD og unit testing generelt.

FORDELE

  • Testkode før programkode: I og med at testkoden bliver lavet før programkoden, tvinges udvikleren til at tænke over kravene, inden de begynder at udvikle.
  • Mere produktivt: Forskning foretaget i 2005 viser at programmør, der skriver flere test er mere produktive [2]. Ved at man tager små bider ad gangen (tester et krav/unit ad gangen) er det nemmere at overskue, og dermed fejlrette. Det er nemmere at skulle rette i en metode på tre linjer kode end en program fil på flere tusind linjer kode.
  • Mere tillid: Alle metoder/funktionaliteter er gennemtestet, og det giver en større grad af tillid til koden.
  • Hurtigere: TDD giver mere kode i form af testkode – dog har undersøgelser foretaget af IBM vist, at det tager kortere tid eller lige så lang tid med TDD som uden [3]. Desuden viste undersøgelserne at udviklingen med TDD havde resulteret i færre fejl. Mange fejl blev opdaget tidligere, og nåede derfor ikke at blive store og ressourcekrævende (tidskrævende).
  • Lavere kobling:  Funktionaliteterne deles op i små bider og testes. De skal kunne testes individuelt, og det resulterer i lavere kobling samt mere fokuserede klasser.
  • Øget programforståelse: Undersøgelser foretaget af bl.a. Ried Kaufmann har vist at TDD at med til at give en øget programforståelse og dermed mere selvtillid. Udvikleren tør rette i koden, da man hurtigt kan se, hvis og hvor det fejler.
  • Eksempelkode: Testkoden er et eksempel på, hvordan udvikleren har tænkt sig at programkoden skal anvendes.

Træerne vokser desværre ikke helt ind i himlen, så TDD har også nogle ulemper.

ULEMPER

  • Blind spot: Ofte samme udvikler som laver testkode og programkode. Det giver den fordel, at man ikke skal sende sine krav ned til test-afdelingen og vente på at de udfærdiger ens tests, men også den ulempe, at du kan stirre dig blind på koden samt overse visse elementer og ligefrem have misforstået opgaven. Den “blinde vinkel” kan minimeres ved at bruge en af eXtreme Programmings andre arbejdspraksisser, parprogrammering. På denne måde får man et sæt ekstra øjne på koden.
  • En for alle, alle for een: TDD virker kun optimalt, hvis hele udviklingsteamet er indstillet på at bruge det. Hvis man har én der modarbejder det, har man tre muligheder:
    1. Man kan forsøge at overbevise personen til at arbejde efter TDDs principper.
    2. Man kan smide personen ud af sit udviklingsteam.
    3. Man kan droppe at bruge TDD.
  • Falsk sikkerhed: TDD kan give en falsk følelse af sikkerhed. I og med at man tester og ser sine test bestå, kan det give en følelse af at ens programkode spiller. Der kan dog stadig være masser af fejl, og det er derfor vigtigt ikke at glemme sine andre tests; accepttest, integrationstest etc.
  • Lang indlæringsproces: Egne erfaringer har vist, at hele TDD-tankegangen kan være svær at vende sig til og indføre i et udviklingsteam, og at det tager tid før man ser skoven for bare træer.

Afrunding

TDD ville bestemt have gavnet vores produkt og proces. Når man benytter sig af TDD får man ryddet op i sin kode løbende, og står ikke tilbage med rodet og dubleret kode. Samtidig er det nemt for andre at overtage koden og lave tilføjelser, idet testkoden vil verificere om en rettelse medfører fejl og hvorhenne fejlen opstår. Med TDD får man mere indsigt i koden, da man altid ved hvilken metode, der fejler, når der fejles. Man undgår derved at bruge en masse tid på at debugge sin kode igennem. Samtidig er TDD med til at sikre at din kode kan testes og styrer færdighedsgraden af dit program. Når alle tests/krav gennemføres er man færdig.
Det kan dog være svært at teste på større systemer med database og GUI-elementer. Her kan man laver Mock Objekter [4] for at simulerer en væremåde. Dog har det den ulempe, at fx vil den faktiske database aldrig være blevet testet af selve TDD processen, hvorfor mange udvikler mener, at man skal adskille disse test fra sine TDD unit tests, og henviser til dem som integrationstests [5]. Når man laver sine tests, er det vigtigt at have styr på sine krav. Uden krav kan man ikke lave sin testkode.

Teksten er forfattet på baggrund af at lære mere om TDD, og lagt online for at andre muligvis kunne få glæde af den viden jeg tilegnede mig. Teksten giver ingen dybdegående viden om TDD og dens brug, men kradser lidt i overfalden, og giver forhåbelig læseren en ide om, hvad TDD er.  Jeg har ganske vist lige overstået min afsluttende eksamen, men modtager derfor alligevel gerne ris/ros på det skrevne.