T-76.5158 SEPA päiväkirja Ryhmä 14 Automatisoitu yksikkötestaus Mikko Luukkonen, 60549T Lauri Helkkula, 62820H Matti Eerola, 60686A
Versiohistoria Versio Pvm Tekijä(t) Kuvaus 0.3 25.11.2007 Luukkonen, Helkkula Vastauksia kysymyksiin & tarkennuksia 0.2 24.11.2007 Eerola Tarkennusta 0.1 19.11.2007 Luukkonen Ensimmäinen versio
Sisällysluettelo 1. Johdanto 2. Käyttöönotto 3. Kokemukset ja muutokset
1. Johdanto Ohjelmistokehityksessä testaus on tärkeässä roolissa ja siihen tulisi tämän takia panostaa. Automatisoidulla yksikkötestauksella voidaan pienentää käsin tehtävän testauksen työmäärää ja täten testaukseen kohdistetut resurssit voidaan mahdollisesti käyttää tehokkaammin hyödyksi. Automatisoitu yksikkötestaus valittiinkin aiheeksi, koska siitä ei ollut kenelläkään ryhmän jäsenistä aikaisempaa kokemusta. Tavoitteena on selvittää, miten automatisoitu yksikkötestaus käytännössä toimii, millaisissa projekteissa siitä on hyötyä, mitä haittoja sen voi seurata ja minkälaisia työkaluja on tarjolla. Ongelman kuvaus: Kuinka kehitettävän ohjelmakoodin yksikkötestauksen voisi hoitaa tehokkaammin ja kattavammin käyttäen vähemmän resursseja. Kehittäjillä pitäisi olla myös jonkinlainen yhteinen kuva ohjelmiston tilasta. Ehdotettu ratkaisu: Automatisoitu yksikkötestaus, joka tässä tapauksessa kattaa ohjelmiston jatkuvan integraation tähän tarkoitukseen pyhitetyn palvelimen ja työkalujen avulla. Työkaluina käytämme jatkuvan integraation alustaa CruiseControl.NET, joka on suunniteltu.net-teknologialla kehitetyn ohjelmiston integraatioon. Kyseinen ohjelma pyörii omalla integraatiopalvelimellaan ja tarkistaa versionhallinnan tilan säännöllisin väliajoin. Havaitessaan päivityksen lähdekoodiin, CruiseControl.NET tekee uuden käännöksen tästä ja ajaa testit. Testien laatimisessa ja ajossa käytetään hyväksi NUnit-työkalua. NUnit-työkalu tarjoaa jo itsessään yksikkötestien automatisoinnin siten, että kehittäjien ei tarvitse suorittaa testejä ajamalla ohjelmaa debug-moodissa ja tarkastella annettujen syöttöjen tuloksia. He voivat yksinkertaisesti kirjoittaa testit lähdekoodiin, sisältäen syöttöarvot ja odotetut tulokset, ja tallentaa nämä omaan testikokoelmaansa, jota voi NUnit:lla ajaa napin painalluksella milloin tahansa. CruiseControl.NET tarjoaa lisäksi apua integraatiotestaukseen ja tämän tulosten kommunikointiin kaikille kehittäjäryhmän jäsenille yhteisen palvelimen kautta. CruiseControl.NET hyöty seuraa ohjelmointiprosessin noudattamisesta ja jatkuvasta, jopa päivittäisestä, ohjelmakoodin integroinnista ja testikokoelmin ajosta. Tällä tavalla kehittäjät voivat olla varmoja, että muutokset lähdekoodiin eivät riko aikaisemmin kehitettyä toiminnallisuutta. Tällainen testausmenetelmä vie NUnit:n kaltaisen automatisoidun yksikkötestauksen askeleen pidemmälle eli seuraavalle testaustasolle. Nyt kehittäjäryhmä saa ajankohtaista palautetta koko ohjelmiston toimivuudesta sen lisäksi, että heillä on varmuus ohjelmiston erillisten yksiköiden oikeanlaisesta toteutuksesta. Ohjelmistokirjan käyttöliittymän puuttuminen tai keskeneräisyys ei estä ohjelmiston toimivuuden tarkastelua syötteiden ja odotettujen tulosten kannalta, ainoastaan käytettävyyden. Voidaan nimittäin tehdä driverit ja stubit kehitetylle ohjelmakirjaston yksiköille eli luokille, jotta nähdään että luokat käsittelevät vastaanottamaansa tietoa oikein ja myös palauttavat odotettuja arvoja. Viitteitä: Automatic Integration with CruiseControl.NET, NAnt and NUnit (King 2005), http://dotnet.syscon.com/read/143301.htm Continuous Integration (Fowler 2006), http://martinfowler.com/articles/continuousintegration.html
2. Käyttöönotto 2.1 Kuvaus menetelmästä Automaattisen yksikkötestauksen käyttöönotto alkaa jakamalla kehittäjille ohjeet automaattisten yksikkötestien tekemisestä. Yksikkötestausta on käsitelty laadunvarmistusdokumentissa ja testitapausten suunnittelusta on ohjeita "Testitapausten suunnittelu NUnitilla"-dokumentista. Jo ensimmäisen iteraation alussa projektiin lisättiin koodirungon lisäksi esimerkkitestitapauksia NUnitille. Niiden avulla kehittäjän pitäisi pystyä tekemään toimivia testitapauksia NUnitille ja lisäksi tekemään niistä ohjeiden avulla tarpeeksi laadukkaita. Jatkuvan integraation testausmenetelmä, sisältäen NUnit:n käytön, on tarkoitettu erityisesti tämän projektin kaikille kehittäjille, mutta myös SE-triio käyttää menetelmää ohjelmiston tilan seuraamiseen ja testaukseen. Integraatiopalvelin on projektiryhmän käytössä osoitteessa http://82.130.29.47/ccnet (Lauri Helkkulan tietokoneella. IP voi muuttua. Tietokone ei usein ole öisin päällä.). Integraatiopalvelin tarkistaa automaattisesti tietyin väliajoin lähdekoodin tilan versionhallinnasta. Jos lähdekoodia on päivitetty, tekee palvelin automaattisesti käännöksen ja ajaa testit. Tästä seuraa raportti viimeisimmän käännöksen ja ajettujen testien tilasta. Kehittäjät hakevat versionhallinnasta uusimman lähdekoodin ja testit ja tekevät muutokset näihin. Kun kehittäjän tekemät muutokset omassa lähdekoodin kopiossa kääntyvät ja testit menevät läpi, hakee tämä versionhallinnasta uusimman lähdekoodin. Jos käännös ja testiajot suoriutuvat onnistuneesti tämänkin jälkeen, voi kehittäjä komitoida lähdekoodin versionhallintaan. Tämän jälkeen kehittäjä vielä varmistaa, että integraatiopalvelin suorittaa käännöksen ja testit onnistuneesti. Mikäli integraatiopalvelin raportoi virheistä, kehittäjän tehtävä on korjata nämä mahdollisimman pian ja komitoida versionhallintaan vakaa, toimiva käännös. Projektiryhmäläiset, erityisesti SE-kolmikko, saavat ajankohtaista tietoa ohjelmiston tilasta seuraamalla integraatiopalvelimen raportteja. Tarkemmat kehittäjille suunnatut CruiseControl.NET:n käyttöohjeet löytyvät Ohjelmointiprosessi-dokumentista.
2.2 Ajankäyttösuunnitelma "T-76.5158 should be done as a pair and requires about 40 hours of effort per person. Scope the SEPA work to 15 hours per person, which does NOT include using the practice. In addition, spend 25 extra hours per person to the T-76.4115 project either experimenting with the SEPA practice or doing any other useful work for the project." http://www.soberit.hut.fi/t-76.4115/07-08/instructions/sepa.html Suunnittelu (15 h): 5 h Opettelu, CC.Net asennus 2 h Suunnittelu Iteraatio 1 2 h Suunnittelu Iteraatio 2 3 h Ohjeiden teko 3 h Vara-aikaa suunnittelulle Menetelmän harjoittaminen ja analyysi (25 h): 12 h Päiväkirja & viikoittaiset tehtävät (1h /viikko) 10 h Raportit (I1 & I2) 3 h Vara-aikaa: Pohdiskellaan lisää asioita raporttiin ja ehkä myös CC.Net-käytön opastusta. ----------------- 40 h Yhteensä Aikataulu SEPAn palautusten osalta: 25.11.2007 Suunnitelma 07.12.2007 Raportti 1 xx.03.2008 Raportti 2 3. Kokemukset ja muutokset 3.1 Projektin suunnittelu Projektin suunnittelu-vaiheessa etsittiin sopivia työkaluja, joilla automaattista yksikkötestausta voi tehdä C#- ohjelmointikielelle ja.net-ympäristöön. Vaiheessa ei vielä noudatettu kuvattuja käytäntöjä, koska ohjelmointiakaan ei tapahtunut. Ainoa tieto, jota saatiin kerättyä, oli kokemukset työkalun sopivuudesta tehtävään. Nekin perustuivat vain nopeaan testailuun, eikä kokemuksiin oikeiden käytäntöjen yhteydessä. Alustavasti NUnit vaikutti melko toimivalta ratkaisulta. Ainoa huono puoli työkalussa oli se, että sen integrointiin kehitystyökalun kanssa ei ollut saatavilla ilmaisia ohjelmistoja kaupallisiin projekteihin. Jää nähtäväksi miten häiritsevänä kehittäjät kokevat sen, että kehittäjän täytyy vaihtaa sovellusta, kun hän siirtyy ohjelmoinnista testien suorittamiseen. CruiseControl.Net-työkaluun ja jatkuvan integraation (eng. Continuous Integration) käsitteeseen ei oltu tutustuttu aikaisemmin. 3.2 Iteraatio 1 Iteraation alussa osa testeistä ei mennyt pitkään aikaan läpi ja se selvästi heikensi yksikkötestien
hyödyllisyyttä. Se myös vaikeutti hieman ohjelman ja testien kehittämistä, koska omien muutoksien aiheuttamista virheistä ei voinut olla niin varma. Kun ohjelma saatiin siihen tilaan, että kaikki olemassa olevat testit menivät läpi, ohjelmointiin tuli enemmän varmuutta, koska muutoksista aiheutuneet virheet nähtiin heti. Integraatiopalvelin saatiin toimimaan halutulla tavalla 19.11.2007, joten sitä ehdittiin käyttää tässä iteraatiossa noin kahden ja puolen viikon ajan. Kaikkien testien ja epäonnistuneiden testien lukumäärä integraatiopalvelimen käytön aikana ensimmäisessä iteraatiossa: 19.11: 5 onnistunutta testiä, 3 epäonnistunutta 20.11: 6, 4 25.11: 6, 1 27.11: 7 28.11: 8, 1 29.11: 9, (ei ajettu) 1 30.11: 10, (ei ajettu) 1 02.12: 12, (ei ajettu) 1 03.12: 17, 1 04.12: 18 05.12: 18 Tilasto kertoo kuinka yksikkötestejä on kirjoitettu aluksi hitaalla tahdilla, mutta kiihtyen kohti ensimmäisen iteraation loppua. Integraatiopalvelin osoittautui erittäin hyödylliseksi sellaisissa tapauksissa, että kehittäjä unohti siirtää osan tiedostoista versionhallintaan, jolloin kehittäjän omat testit näyttivät menevän läpi, mutta versionhallinnassa olevat testit eivät enään menneet läpi. Palvelimelta pystyi helposti katsomaan, mitkä olivat muutokset jotka rikkoivat testit. Sen tiedon avulla pystyi pyytämään oikeaa henkilöä lisäämään tiedostot versionhallintaan. Dokumentin lopussa on kuvakaappaus CruiseControl.Net:n kääntöraportista, johon siis kuuluvat myös testien suorittaminen. Kuvasta näkyy, kuka on tehnyt muutoksia sitten edellisen tarkistuksen, ja että kääntäminen ei mennyt läpi, koska yhtä tiedostoa ei löytynyt. Syy on helppo tunnistaa: uutta tiedostoa ei ole muistettu lisätä versionhallintaan. Eräs ongelma integraatiopalvelimen käytössä liittyi tietokantojen käyttöön ja päivittämiseen. Usein ohjelmistoa kehitettäessä myös tietokanta kehittyy, ja täten myös integaraatiopalvelimen käyttämää tietokantaa pitäisi päästä helposti päivittämään. Meidän ympäristössämme integraatiopalvelimen tietokantaa pystyi päivittämään ainoastaan palvelimen ylläpitäjä. Todellisessa projektissa tämä ongelma olisi ratkennut helposti sillä, että kehitys tapahtuisi yhdessä keskitetyssä paikassa, jossa olisi turvallinen lähiverkko. Tällöin kehittäjä voisi ottaa suoraan yhteyden tietokantapalvelimelle (ilman suuria turvavaatimuksia yhteydelle) ja tehdä tarvitsemansa päivitykset. Julkisen verkon ylitse yhteydet voisi ehkä hoitaa VPN:n (tai vast.) kanssa, mutta pelkästään tähän käyttön VPN:n kaltainen ratkaisu olisi hieman yliampuva. Tehdyt testit ovat olleet hyviä ja ne ovat testanneet sopivalla tavalla testaamaansa asiaa. Testien kattavuus ja monipuolisuus ei kuitenkaan ole vielä järin suuri, vaan testitapaukset on suunniteltu testaamaan perustoiminnallisuutta, siten kuin komponentteja on tarkoitus käyttää. Esimerkiksi olioiden tallennus ja lataus tietokannasta on testattu siten, että tallennettu tieto saadaan samanlaisena ladattua takaisin, mutta metodeille ei ole tehty kaikenlaisia parametreja ja olosuhteita testaavia testejä.
Testiluokkien määrä on vielä alhainen verrattuna "oikeiden" luokkien määrään. Kaikki testit eivät tosin ole puhdasta yksikkötestausta, vaan jotkut testaavat myös luokkien välistä yhteistoimintaa. CruiseControl.NET on hyvä työkalu tässäkin. Huomiota tulee jatkossa kiinnittää siihen, että yksikkötestit tulevat tehtyä jokaiselle vähänkin toiminnallisuutta sisältävälle luokalle, koska jo olemassa olevien testien olemassaolo on osoittautunut erittäin hyödylliseksi, varsinkin kun kehittäjillä ei aina ole suoraa kommunikointiyhteyttä. Toisen iteraation aikana voinemme siirtyä yksikkötesteistä tasoa ylemmäksi, koska itse tietomalli on suurilta osin valmis ensimmäisen iteraation jälkeen. Suunniteltu ohjelmointiprosessi on ollut käytössä melko hyvin. Aina ei ole ollut mahdollista käyttää CC.Netpalvelinta, koska palvelin ei ole ollut päällä, eikä sitä ole aina muistettu käyttää muutosten versionhallintaan viemisen jälkeen. Mitään vakavia ongelmia ei ole viety versionhallintaan, joka osaltaan kertoo, että NUnitilla on ajettu testit omassa ympäristössä prosessiohjeen mukaisesti. CC.Net:n unohtaminen prosessissa ei ole kovin vakava juttu, sillä se myös tarkistaa ajastetusti versionhallinnasta onko muutoksia tullut ja ajaa testit tarvittaessa uudestaan. 3.3 Iteraatio 2 3.4 Yhteenveto Ehdotetun ratkaisun toimivuuden tarkasteluun käytetään seuraavia kysymyksiä ja menetelmiä: kuinka paljon testejä on suunniteltu? mikä on testien koodirivikattavuus? ovatko testit oikeanlaisia eli löytävätkö ne tehokkaasti virheitä ohjelmistosta? mitä testit itseasiassa kertovat ohjelmiston tilasta? kuinka kauan ohjelmisto on keskimäärin "Failed"-tilassa, eli integraatio on epäonnistunut, ennen kuin virheet korjataan? ovatko kehittäjät nuodattaneet ohjelmointiprosessia? muiden ryhmäläisten haastattelu heidän kokemustensa kartoittamiseksi Lisäksi on syytä tarkastella jatkuvan integraation vaatimuksia: resurssit työkalujen ylläpito testien teko ohjelmointiprosessin noudattaminen Vaatimukset eivät luonnollisesti saa ylittää menetelmällä aikaan saatuja hyötyjä, jotta käytäntö olisi oikea ja tehokas ratkaisu alkuperäiseen ongelmaan. Menetelmän käytön riskejä edustaa erityisesti testien väärinkäyttö eli liian vähän testejä tai vääränlaisia testejä.
Kuva1. Kuvakaappaus CruiseControl.NET:n käyttöliittymästä.