Testilähtöinen ohjelmistokehitys. Testilähtöinen ohjelmistokehitys. TDD Testilähtöinen ohjelmistokehitys. Testi! Testi. Test-Driven Development, TDD

Samankaltaiset tiedostot
Test-Driven Development

Test-Driven Development

Testilähtöinen ohjelmistokehitys. Testilähtöinen ohjelmistokehitys. TDD Testilähtöinen ohjelmistokehitys. Testi! Testi

Ohjelmointi 2 / 2010 Välikoe / 26.3

Yksikkötestaus. import org.junit.test; public class LaskinTest public void testlaskimenluonti() { Laskin laskin = new Laskin(); } }

Tarjolla tänää: Ohjelmiston toteutuksesta. Kuinka tulla hyväksi ohjelmoijaksi? CRC-kortit. Testilähtöinen kehittäminen JOT2007. Uudelleenrakentaminen

Ohjelmistojen mallintaminen. Luento 11, 7.12.

Ohjelmointi 1 / 2009 syksy Tentti / 18.12

ITKP102 Ohjelmointi 1 (6 op)

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmointi 2 / 2011 Välikoe / 25.3

ITKP102 Ohjelmointi 1 (6 op)

Testivetoinen ohjelmistokehitys

Ohjelmointi 1 C#, kevät 2013, 2. tentti

JReleaser Yksikkötestaus ja JUnit. Mikko Mäkelä

1. Mitä tehdään ensiksi?

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

Ohjelmoinnin perusteet Y Python

Eclipse ja JUnit-ohjelmoijatestit

Ohjelmointi 2 / 2008 Välikoe / Pöytätestaa seuraava ohjelma.

Metodien tekeminen Javalla

JUnit ja EasyMock (TilaustenKäsittely)

20. Javan omat luokat 20.1

SEPA diary. Dokumentti: SEPA_diary_PK_HS.doc Päiväys: Projekti: AgileElephant Versio: V0.3

Sisällys. 20. Javan omat luokat. Java API. Pakkaukset. java\lang

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

Toisessa viikkoharjoituksessa on tavoitteena tutustua JUnit:lla testaukseen Eclipse-ympäristössä.

Pong-peli, vaihe Aliohjelman tekeminen. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 3/7. Tämän vaiheen aikana

Ohjelmointi 1 C#, kevät 2013,

Java-kielen perusteita

Java-kielen perusteet

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

Java-kielen perusteet

Ohjelmointi 2, välikoe

Ohjelmointi 1 C#, kevät 2014, tentti

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Ohjelmoinnin perusteet Y Python

13. Loogiset operaatiot 13.1

58160 Ohjelmoinnin harjoitustyö

Tehtävä 1. Tehtävä 2. Arvosteluperusteet Koherentti selitys Koherentti esimerkki

Harjoitus 2 (viikko 45)

Ohjelmoinnin jatkokurssi, kurssikoe

8/20: Luokat, oliot ja APIt

17. Javan omat luokat 17.1

Olio-ohjelmointi Javalla

Java kahdessa tunnissa. Jyry Suvilehto

Tietorakenteet ja algoritmit syksy Laskuharjoitus 1

1. Olio-ohjelmointi 1.1

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

1 Tehtävän kuvaus ja analysointi

Taulukot. Taulukon määrittely ja käyttö. Taulukko metodin parametrina. Taulukon sisällön kopiointi toiseen taulukkoon. Taulukon lajittelu

Javan perusteita. Janne Käki

Ohjelmoinnin perusteet, kurssikoe

Harjoitus 4 (viikko 47)

15. Ohjelmoinnin tekniikkaa 15.1

ITKP102 Ohjelmointi 1 (6 op)

Rinnakkaisohjelmointi kurssi. Opintopiiri työskentelyn raportti

Olion elinikä. Olion luominen. Olion tuhoutuminen. Olion tuhoutuminen. Kissa rontti = null; rontti = new Kissa();

Ohjelmoinnin perusteet, syksy 2006

5. HelloWorld-ohjelma 5.1

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Yksikkötestaus. Kattava testaus. Moduulitestaus. Ohjelman testaus. yksikkotestaus/ Seija Lahtinen

Harjoitus 3: Flash-komponenttiarkkitehtuuri ( )

Java-kielen perusteet

1. Kun käyttäjä antaa nollan, niin ei tulosteta enää tuloa 2. Hyväksy käyttäjältä luku vain joltain tietyltä väliltä (esim tai )

Pong-peli, vaihe Koordinaatistosta. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 2/7. Tämän vaiheen aikana

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

14. Hyvä ohjelmointitapa 14.1

Interaktiivinen tarinankerronta

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

17. Javan omat luokat 17.1

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Vasen johto S AB ab ab esittää jäsennyspuun kasvattamista vasemmalta alkaen:

Algoritmit 1. Demot Timo Männikkö

1. Omat operaatiot 1.1

Tietorakenteet. JAVA-OHJELMOINTI Osa 5: Tietorakenteita. Sisällys. Merkkijonot (String) Luokka String. Metodeja (public)

Automaattinen yksikkötestaus

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

Merkkijonon tutkiminen matches-metodilla

CODEONLINE. Monni Oo- ja Java-harjoituksia. Version 1.0

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Listarakenne (ArrayList-luokka)

13. Loogiset operaatiot 13.1

Harjoitus 5 (viikko 48)

7. Näytölle tulostaminen 7.1

Vertailulauseet. Ehtolausekkeet. Vertailulauseet. Vertailulauseet. if-lauseke. if-lauseke. Javan perusteet 2004

Ohjelmoinnin perusteet Y Python

12. Javan toistorakenteet 12.1

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

TT00AA Ohjelmoinnin jatko (TT10S1ECD)

ITKP102 Ohjelmointi 1 (6 op), arvosteluraportti

Ohjelmoinnin perusteet Y Python

Luokka Murtoluku uudelleen. Kirjoitetaan luokka Murtoluku uudelleen niin, että murtolukujen sieventäminen on mahdollista.

Ohjelmistotekniikan menetelmät, koe

Harjoitustyön testaus. Juha Taina

Ohjelmoinnin perusteet Y Python

Taulukot. Jukka Harju, Jukka Juslin

Luokat ja oliot. Ville Sundberg

Sisällys. Yleistä attribuuteista. Näkyvyys luokan sisällä ja ulkopuolelta. Attribuuttien arvojen käsittely aksessoreilla. 4.2

Transkriptio:

Testilähtöinen ohjelmistokehitys Kevät 2010 Jyväskylän yliopisto Testilähtöinen ohjelmistokehitys Test-Driven Development, TDD Tehdään ensin testi, sitten vasta koodi. 1 2 TDD Testilähtöinen ohjelmistokehitys Testi! Testi Tarkoituksena ei ole keksiä kaikkia mahdollisia tapoja löytää virheitä, vaan suunnitella ja toteuttaa vaatimukset täyttävä ohjelma. TDD ei ole testausta, vaan kehitystä! TDD ohjaa ajattelemaan ensin. Testilähtöisessä ohjelmoinnissa testien avulla suunnitellaan ohjelma. Ensin tehdään testi, sitten vasta ohjelma. Toimitaan valmiiden vaatimusten mukaan, eikä koeteta keksiä uusia samalla. 3 4

Testi! Testi Mitä saavutetaan Erona yksikkötestaukseen on, että yksikkötestauksessa varmistetaan ohjelman toiminta. Testi tehdään ohjelman jälkeen. Kaikki poikkeukset ja erikoisuudet koetetaan löytää ja testata. TDD:n testejä voi käyttää yksikkötestauksen apuna! Tulos 1: Voidaan olla varmoja siitä, että ohjelma toimii (testien mukaan). Tulos 2: Saadaan esimerkkejä ohjelman rajapintojen käytöstä. Tulos 3: Ohjelma on ylläpidettävämpi ja testattavampi. 5 6 Negatiivisesti Historia Tulos 1: Ohjelma toimii vain osittain, eikä voida osoittaa virheettömyyttä. Tulos 2: Esimerkkejä, jotka ovat kaukana lähdekoodista. Tulos 3: Testejä voi olla työlästä ylläpitää. Pitääkö testit testata? Lähtöisin samasta sylttytehtaasta kuin XP (= Extreme Programming), ja Smalltalkista (SUnit), eli Ward Cunninghamilta. Mitkään XP:n käytännöt eivät ole uusia (paitsi "tehdään kaikki 110%"), ei tämäkään. Nykyään: xunit työkalut useille kielille. Muita nimiä: yksikkötestaus, ohjelmoijatestaus. 7 8

TDD Vaiheet TDD säännöt 1. RED Kirjoita testi. Aja testi, eikä se mene läpi. 2. GREEN Muuta tai tuota ohjelmaa niin kauan, että testin ajo menee läpi. 3. REFACTOR Siivoa koodi (eli uudelleenrakenna se). Toista ylläolevia, kunnes ohjelma on valmis. Älä kirjoita riviäkään uutta koodia, ennen kuin sinulla on sille kirjoitettuna testi, jonka ajo ei mene läpi (ei onnistu tai palauttaa virheen). Kirjoita toteutus selkeästi ja liioitellunkin yksinkertaisesti. Poista monikerrat siivoa testit ja toteutus. 9 10 Sääntöjen seuraukset Muita seurauksia Suunnittelu on interaktiivista. Ajettava ohjelma antaa palautteen, jonka mukaan edetään. Teet itse testisi, sillä ei ole aikaa odottaa toisten kirjoittavan niitä. Kehitysympäristön on annettava nopea palaute muutoksista. Suunniteltava korkean koheesion ja löyhän kytkennän komponentteja, jotka ovat siten testattavia. Laatuosasto (QA) voi tehdä työnsä proaktiivisesti, eikä reaktiivisesti. Paremmat arviot, vähemmän yllätyksiä. Kommunikointi kehittäjien välillä helpompaa ja nopeampaa (aina toimiva koodi esillä). Uusi versio uusin ominaisuuksin tarjolla asiakkaalle joka päivä. 11 12

Miksi näin ei tehdä? Pelko "Tämä on tyhmää ja hidastaa kehitystä!" "Tämä estää ajattelun / suunnittelun!" "Tämä rikkoo mun flown!" Taustalla pelko: "Tämä on liian hankala ominaisuus, enkä tiedä mistä aloittaa!" Seurauksena epävarmuus, kommunikoimattomuus, ujous ja äreys, kun pitäisi opetella, kommunikoida, hakea rohkeasti apua. TDD auttaa, se antaa varmuuden siitä, että se mitä on tehty toimii. 13 14 Kritiikkiä 2. Kuinka alkuun? Aloita nyt heti, ei kohta tai huomenna. "Testi ja koodi liian kaukana toisistaan!" "Liian vaikeaa kirjoittaa!" / "Liikaa kirjoitettavaa!" Vastaus: ComTest (Lappalainen et al.), josta myöhemmin lisää. Jos et voi aloittaa puhtaalta pöydältä, ala tekemään testejä bugikorjauksille ja uusille ominaisuuksille. Joitain asioita on hankalaa testata (GUI, DB), tai erittäin hankalaa testata (salaus, samanaikaisuus). Tekemällä oppii! (Harjoitteluun esim. katat.) 15 16

Bob-sedän neuvoja TDD Vaiheet Bob-setä on "Uncle Bob", eli Robert Martin. Kymmenen minuuttia testiajojen välillä on liian pitkä aika. Emme korjaa sotkuista koodia, koska pelkäämme rikkovamme jotain. Testilähtöisyys osoittaa heti, jos jotain rikkoontuu. (Toimivaa ohjelmaa on eri ikävä testata.) 1. RED Kirjoita testi. Aja testi, eikä se mene läpi. 2. GREEN Muuta tai tuota ohjelmaa niin kauan, että testin ajo menee läpi. 3. REFACTOR Siivoa koodi (eli uudelleenrakenna se). Toista ylläolevia, kunnes ohjelma on valmis. 17 18 Kirjoita testi Muokkaa, kunnes toimii Kirjoita testi selkeästi. Kirjoita se, kuten kirjoittaisit esimerkkiä (testattavan) ominaisuuden käytöstä. Behaviour-driven development? Ei kirjoiteta kuten yksikkötesti! UB: Kirjoita vain sen verran, että testi ei mene läpi. Yksinkertaisin koodi, millä testi toteutuu! Älä pelkää tyhmiä ratkaisuja tai järjetöntä koodia. Koodin on oltava yksinkertaista. Liian hienoa kikkailua tulee välttää. UB: Älä kirjoita mitään, mille ei ole testiä. UB: Kirjoita vain sen verran, että testi menee läpi. 19 20

Siivoa ohjelmakoodi Variaatio Poista turhat kikkailut ja tuplakoodi. Tuplakoodin huomaaminen voi olla hankalaa. Siisti myös testit! Kirjoitetaan yksi rivi testistä. Ajetaan testi, muokataan koodia, kunnes testi menee läpi. Kirjoitetaan seuraava rivi testistä.... toistetaan, kunnes valmis. 21 22 JUnit = Java + TDD JUnit testit Jos JUnitia ei löydy kehitysympäristöstäsi, vaihda kehitysympäristöä. Testit voi tehdä nykyään erilliseen luokkaan tai toteutuskoodin joukkoon. Testaava metodi merkitään @org.junit.testtarkentimella. Metodi on julkinen, eikä palauta mitään, eli esimerkiksi: @Test public void testlisääjäsen() { /* */ } Lause import org.junit.assert.* tuo testausmetodit käyttöösi, esimerkiksi: assertequals( Testikuvaus, odotettuarvo, testattavaarvo) 23 24

JUnit testin ajo JUnit apuja Testien ajo palauttaa vihreän palkin, jos testit menivät läpi. Jos eivät, tulee punainen palkki ja virheilmoitus, joka kertoo virheen paikan. Assert-metodeille voi myös antaa kolmantena parametrina merkkijonon, joka selittää testin. Se tulostetaan virheilmoituksen yhteydessä. Jokainen testimetodi suoritetaan erikseen. Metodi, joka on merkitty tarkenteella @org.junit.before suoritetaan ennen jokaista testimetodin ajoa. Metodi tarkenteella @org.junit.after suoritetaan jokaisen testimetodin ajon jälkeen. Konstruktori suoritetaan vain kerran 25 26 Hämärät nurkat Lyhyesti Kuinka opetetaan TDD:tä? Koska TDD:tä tehdään oikein? Mikä on arkkitehtuurin osuus? Sitooko arkkitehtuuri liikaa, vai onko arkkitehtuuri perusedellytys TDD:n toiminnalle? TDD mielummin arkkitehtuurin mukaisille osille kuin nollasta aloittaessa. Testi ensin, sitten koodi. Muista siivota. Testilähtöinen kehitys ei ole sama asia kuin perinteinen V-mallin yksikkötestaus. Kehitetään, ei etsitä virheitä. Edustava ote testeistä riittää. ÄLÄ kirjoita TDD-testejä kuten kirjoitat yksikkötestejä! 27 28

Lyhyesti ComTest Tämäkään ei ole hopealuoti! "Mieti! Mieti! Mieti!" Beck: "...TDD on enemmän mielentila...", joten älä tee siitä itsellesi pakkoa tai rasitetta Testit dokumentaation ja metodimäärittelyn yhteyteen. JavaDoc sisältää testin, joka voidaan ajaa. Testi toimii myös esimerkkinä metodin käytöstä. Taipuu helposti myös muille kielille kuin Javalle. 29 30 102 /** 103 * Palauttaa jonon s muotoiltuna vähintään len-pituiseksi 104 * <pre> 105 * Esim: fmt("2",3) => " 2" 106 * fmt("2",-3) => "2 " 107 * </pre> 108 * @param s muotoiltava jono 109 * @param len pituus, negatiivisella vasempaan laitaan, pos. oikeaan 110 * @return muotoiltu jono 111 * 112 * @example 113 * <pre name="test"> 114 * fmt("2",3) === " 2" 115 * fmt("2",-3) === "2 " 116 * fmt("1234",3) === "1234" 117 * </pre> 118 */ 119 public static String fmt(string s,int len) { 120 int needs = Math.abs(len) - s.length() 121 if ( needs <= 0 ) return s 122 String fill = tyhja(needs) 123 if ( len < 0 ) return s + fill 124 return fill + s 125 } // Generated by ComTest BEGIN /** testfmt113 */ @Test public void testfmt113() { // Mjonot: 113 assertequals("from: Mjonot line: 114", " 2", fmt("2",3)) assertequals("from: Mjonot line: 115", "2 ", fmt("2",-3)) assertequals("from: Mjonot line: 116", "1234", fmt("1234",3)) } // Generated by ComTest END 31 32

328 /** 329 * Erottaa jonosta valitun merkin kohdalta alkuosan ja loppuosan. 330 * Alkuosa palautetaan funktion nimessä ja loppuosa jätetään 331 * jonoon. Merkin etsimissuunta voidaan valita (oletuksena alusta päin). 332 * Jos merkkiä ei löydy, palautetaan koko jono ja tyhjennetään jono. 333 * <pre> 334 * Käyttöesimerkki: olkoon aluksi string jono,s 335 * 1) jono = "123 456" s = erota(jono) => jono == "456" s == "123" 336 * 2) jono = "123" s = erota(jono) => jono == "" s == "123" 337 * 3) jono = "1 2 3" 338 * while ( jono.length() > 0 ) System.out.print(erota(jono)+",") 339 * => tulostaa 1,2,3, 340 * </pre> 341 * 342 * @param jono jono jota pilkotaan 343 * @param merkki merkki jonka kohdalta katkaistaan 344 * @param etsitakaperin etsitäänkö merkki oikealta vasemmalle 345 * @return merkkiä edeltävä jono 346 * 347 * @example 348 * <pre name="test"> 349 * StringBuffer jono= new StringBuffer("123 456") String s 350 * s = erota(jono) jono.tostring() === "456" s === "123" 351 * 352 * jono = new StringBuffer($jono1) 353 * s = erota(jono,$merkki,$suunta) 354 * jono.tostring() === $jono2 s === $s 355 * 356 * $jono1 $merkki $suunta $jono2 $s 357 * --------------------------------------------------- 358 * "123" ' ' false "" "123" 359 * --- ' ' false "" "" 360 * --- ' ' false "" "" 361 * "123 456" ' ' false "456" "123" 362 * --- ' ' false "" "456" 363 * --- ' ' false "" "" 364 * "12 34 6" ' ' false "34 6" "12" 365 * --- ' ' false "6" "34" 366 * --- ' ' false "" "6" 367 * --- ' ' false "" "" 368 * "12 34 6" ' ' true "6" "12 34" 369 * --- ' ' true "" "6" 370 * --- ' ' true "" "" 371 * 372 * erota((stringbuffer)null,' ',false) === "" 373 * </pre> 374 */ 33 34 // Generated by ComTest BEGIN /** testerota348 */ @Test public void testerota348() { // Mjonot: 348 StringBuffer jono= new StringBuffer("123 456") String s s = erota(jono) assertequals("from: Mjonot line: 350", "456", jono.tostring()) assertequals("from: Mjonot line: 350", "123", s) jono = new StringBuffer("123") assertequals("from: Mjonot line: 358", "", jono.tostring()) assertequals("from: Mjonot line: 358", "123", s) assertequals("from: Mjonot line: 359", "", jono.tostring()) assertequals("from: Mjonot line: 359", "", s) assertequals("from: Mjonot line: 360", "", jono.tostring()) assertequals("from: Mjonot line: 360", "", s) jono = new StringBuffer("123 456") assertequals("from: Mjonot line: 361", "456", jono.tostring()) assertequals("from: Mjonot line: 361", "123", s) assertequals("from: Mjonot line: 362", "", jono.tostring()) assertequals("from: Mjonot line: 362", "456", s) assertequals("from: Mjonot line: 363", "", jono.tostring()) assertequals("from: Mjonot line: 363", "", s) jono = new StringBuffer("12 34 6") assertequals("from: Mjonot line: 364", "34 6", jono.tostring()) assertequals("from: Mjonot line: 364", "12", s) assertequals("from: Mjonot line: 365", "6", jono.tostring()) assertequals("from: Mjonot line: 365", "34", s) assertequals("from: Mjonot line: 366", "", jono.tostring()) assertequals("from: Mjonot line: 366", "6", s) assertequals("from: Mjonot line: 367", "", jono.tostring()) assertequals("from: Mjonot line: 367", "", s) jono = new StringBuffer("12 34 6") s = erota(jono,' ',true) assertequals("from: Mjonot line: 368", "6", jono.tostring()) assertequals("from: Mjonot line: 368", "12 34", s) s = erota(jono,' ',true) assertequals("from: Mjonot line: 369", "", jono.tostring()) assertequals("from: Mjonot line: 369", "6", s) s = erota(jono,' ',true) assertequals("from: Mjonot line: 370", "", jono.tostring()) assertequals("from: Mjonot line: 370", "", s) assertequals("from: Mjonot line: 372", "", erota((stringbuffer)null,' ',false)) } // Generated by ComTest END Kokemuksia ComTestin käytöstä ComTest kehitettiin, koska JUnitin käyttö Ohjelmointi 2 -kurssilla ei vastannut kurssin luennoijan toivetta. Oppilaat ovat sittemmin käyttäneet ComTestia Ohjelmointi 1 ja 2 kursseilla innokkaammin kuin JUnitia. ComTestin käytöstä ohjelmistoteollisuudessa ei valitettavasti ole kokemusta. 35 36

Linkit & Vinkit Viikkotehtävä http://c2.com/cgi/wiki?testdrivendevelopment JUnit & TDD: http://www.junit.org/ ComTest: https://trac.cc.jyu.fi/projects/comtest Bob-sedän pakinoita: http://butunclebob.com/ ArticleS.UncleBob.TheThreeRulesOfTdd http://theruntime.com/blogs/jacob/archive/2008/01/22/tdd-proveneffective-or-is-it.aspx http://www.infoq.com/interviews/coplien-martin-tdd Kent Beck: Test-Driven Development by Example Keilailu-kata: http://butunclebob.com/ ArticleS.UncleBob.TheBowlingGameKata 1. Tee keilailukata. 2.Tee keilailukata. 3.Tee keilailukata. 4.Tee keilailukata. 5.Tee keilailukata. Voit myös heti aluksi tehdä tehtävät jollain sinulle uudella ohjelmointikielellä! 6.Bonustehtävä: Toista edelliset tehtävät jollain toisella ohjelmointikielellä. 37 38