Testdriven utveckling Januari 2009, KTH Alexander Tarnowski © Acando AB Passion for improvements Teorin bakom testdriven utveckling © Acando AB Passion for improvements Bakgrund Testdriven utveckling började nämnas kring 1999-2000 av Kent Beck I praktiken implementationen av XP:s ”test first” Målet är ”Clean code that works” Ses som ett verktyg för hantering av rädsla och osäkerhet i utvecklingsprocessen Baserat på enhetstest (unit tests) © Acando AB Passion for improvements 1 Testdriven utveckling och XP Värderingar Praktiker Kommunikation Enkelhet Feedback Mod Respekt Principer © Acando AB Sitta tillsammans Teamet Informativ arbetsplats ”Energized work” Parprogrammering Stories Veckocykeln Kvartalscykeln Slack Bygga på 10 minuter Continuous integration Testa först Inkrementell design Passion for improvements TDD strävar efter: ”Clean code that works” Förutsägbarhet. Ingen ”projektsvans”! Dina kolleger litar på dig, och du på dem Lär dig allt du kan av koden Omedelbar feedback Kul att skriva © Acando AB Ron Jeffries Passion for improvements Förutsägbarhet © Acando AB Passion for improvements 2 TDD reducerar: rädsla (och osäkerhet) Rädsla gör oss osäkra Rädsla får oss att kommunicera mindre Rädsla påverkar vår förmåga att ta emot feedback Rädsla gör oss otrevliga © Acando AB Passion for improvements TDD bygger på unit tests Enhetstester... Visar att isolerade komponenter av program fungerar Är isolerade från varandra Och är inte... Prestandatester Stresstester Användbarhetstester <Stoppa in favorit-buzzword som slutar med ”tester” här> © Acando AB Passion for improvements Metodologin Skriv ett test som misslyckas Få testet att köra Ta bort duplicering © Acando AB Passion for improvements 3 TDD:s utvecklingscykel Att skriva ny kod endast om ett automatiserat test misslyckas Och därefter ta bort duplicering Leder till och kräver: Organisk design: körbar kod ger feedback och driver utvecklingen framåt Design med high cohesion och loose coupling Att utvecklarna måste skriva sina egna test Utvecklingsmiljön måste ge snabb feedback © Acando AB Passion for improvements Vad är ett test Testa = utvärdera Vilken logik testar vi? Vilka testdata väljer vi? Bäst att upprepa: tester ska vara oberoende! © Acando AB Passion for improvements Vilken logik testar vi Testa: Villkor Iterationer Sekventiella operationer Polymorfism Testa inte: Tredje parts kod (t ex att JDBC eller en applikationsserver fungerar) ”Too simple to break” © Acando AB Passion for improvements 4 Vilka testdata väljer vi? Enkla assertEquals(5, calc.plus(2, 3)); mot assertEquals(12517294, calc.plus(11286060, 1231234)); Relevanta @Test(expected=NullPointerException.class) public void testInsert() { insertIntoDatabase(null); } kanske inte är bästa testet för void insertIntoDatabase(TransferObject o) { ... } Självförklarande final int addend = 2; final int augend = 3; assertEquals(addend + augend, calc.plus(addend, augend)); © Acando AB Passion for improvements Testtekniker Vi tar oss från rött till grönt genom att: Fejka Uppenbara implementationen Triangulering © Acando AB Passion for improvements Teknik 1: Fejka TestCalculator.java assertEquals(4, calculator.plus(3,1)); Calculator.java int plus(int augend, int addend) { return 4; } © Acando AB Passion for improvements 5 Teknik 2: Uppenbara implementationen Man får faktiskt göra så TestCalculator.java assertEquals(4, calculator.plus(3,1)); Calculator.java int plus(int augend, int addend) { return augend + addend; } © Acando AB Passion for improvements Teknik 3: Triangulering Generalisera om vi har två eller fler fall Använd i svårare fall! TestCalculator.java assertEquals(4, calculator.plus(3,1)); assertEquals(8, calculator.plus(4,4)); Calculator.java int plus(int augend, int addend) { return ???; } © Acando AB Passion for improvements Dåliga tester Mycket setupkod = för stora och komplicerade objekt Duplicerad setup = för många objekt, för hårt kopplade Långa test = kommer inte att köras, åldras och blir fel © Acando AB Passion for improvements 6 Varför reducera duplicering? Urholkar den konceptuella integriteten Försvårar underhåll Vanligaste exemplet: duplicerad logik Näst vanligaste: copy’n paste kod Beroende är sjukdomen, dupliceringen symptomet För en gångs skull! Eliminerar vi symptomet (dupliceringen) minskar vi beroendet (sjukdomen) © Acando AB Passion for improvements Hur stora steg ska man ta? Test transformerar ett abstrakt problem till att ”få testet att funka” Storleken på stegen beror på osäkerheten Vi slutar testa när rädslan och osäkerheten förvandlas till leda TDD handlar inte om att ta små steg, utan om att kunna göra det © Acando AB Passion for improvements Svårt att driva med tester Säkerhetsprogramvara Parallella system Realtidsprogramvara © Acando AB Passion for improvements 7 Argument mot TDD och utvecklardriven testning Tester tar lång tid att skriva Tester tar lång tid att köra En del kod måste testas live När man inte vet vad koden ska göra, så kan man inte testa ”if it compiles then it works” Utvecklare är inte testare! © Acando AB Passion for improvements Sammanfattning Vi får tester att köra genom fejk, triangulering, eller den uppenbara implementationen Borttagning av dupliceringen mellan test och skarp kod driver designen Flytande gräns mellan hur stora stegen mellan test och implementation blir beroende av svårighetsgraden. TDD ersätter: ”Code for today, design for tomorrow” med ”By not considering the future of your code, you make your code much more likely to be adaptable in the future” © Acando AB Passion for improvements Bortom TDD Behavior-driven design Acceptanstestdriven utveckling © Acando AB Passion for improvements 8 Behavior-driven design Publicerades kring slutet av 2007 Order ”test” i testdriven utveckling ställer till med problem Allomfattande språk för analysprocessen: Stories: As a/I want/so that Acceptanskriteria: Given/when/then © Acando AB Passion for improvements Acceptanstestdriven utveckling Ramverk: Concordion, FitNesse Uppbyggda av en specifikation skriven i klartext och en fixtur Specifikationen innehåller parametrar till testfixturen och kommunicerar testets resultat © Acando AB Passion for improvements Att införa TDD: de största problemen Nytt arbetssätt Inlärningskurvorna för teknikerna och verktygen Legacykod Man ser inte nyttan omedelbart © Acando AB Passion for improvements 9 Nytt arbetssätt Kräver disciplin Kräver kunskap: Lätt att testa fel saker Lätt att testa saker fel ”Om det enda man har är en hammare, blir varje problem en spik” Passion for improvements © Acando AB En möjlig inlärningskurva produktivitet ? Valfritt ramverk Databastestning/webbtestning Refactoring Testning av kollaboratörer tid Teori JUnit © Acando AB Passion for improvements Problem med legacykod Inga eller få tester Affärslogik i databasen Felimplemterade ”J2EE patterns” Singletons M m, m m Refactoring! © Acando AB Passion for improvements 10 Hur vi underlättar införandet. Lösningar! Litteratur Mentorskap Några krasher i kritiska otestade system Continuous build © Acando AB Passion for improvements Konsekvenser Man blir ”test infected” Skriver aldrig för mycket kod Designen går mot IoC och ”Clean Code” © Acando AB Passion for improvements Slutsatser och rekommendationer Att lära sig TDD tar ett par månader Inlärningskurvan är knuten till testramverken Svårt att alltid behålla disciplinen Man ”stoppas” av legacykod Testa! Man lär sig testramverken Man lär sig refactoring Man designar kod bättre Att fuska med TDD innebär att vi landar på utvecklardriven testning. © Acando AB Passion for improvements 11