sunnuntai, 21. joulukuu 2014

Testien nimeäminen

Yhtenä päivänä pidin tiimikavereiden kanssa koodausdojoa, jossa aioimme nimetä paremmin vanhoja yksikkötestejä. Testit olivat vasta muutaman viikon vanhoja, mutta pian osoittautui, ettei kukaan enää muistanut pelkän testin nimen perusteella, mitä testin oli määrä tehdä – ei edes testit alunperin kirjoittanut henkilö, joka oli dojossa mukana. Yleensä oli tarpeen lukea koko testifunktio läpi, että testin tarkoitus selviäisi.

Ylläpidon ja vikojen löytämisen kannalta on tärkeää, että testeillä on kuvaavat nimet. Lisäksi testit ovat varsinaisen ohjelmakoodin ohella ainoa, todella paikkansa pitävä dokumentaatio ohjelman toiminnasta. Koodista irrallinen dokumentaatio voi jäädä ohjelmiston kehityksestä jälkeen, mutta testit eivät, mikäli ne ovat toimivia.

Alla on C++-kielinen esimerkki huonosti nimetystä testistä.

TEST(ClientManagerTests, testChange)
{
    //1. Create instance and set number of clients to maximum
    ClientManager myClientManager;
    myClientManager.setClientAmount(10);

    //2. Set new value
    myClientManager.setClientAmount(2);

    //3. Check results
    int value = myClientManager.getClientAmount();
    CHECK(value == 2);
}

Siis testille on hutaistu epäkuvaava nimi ja toiminta selitetään kommenteissa koodin seassa. Kirjoitushetkellä testin nimi on varmaankin tuntunut kirjoittajasta itsestään ihan järkevältä, koska asia on tuoreena mielessä, mutta toisille se ei sano mitään. Niinpä testin tarkoitus selviää vain testin toteutusta lukemalla. Jos toteutus on monimutkainen, testikoodin seassa on mahdollisesti selventäviä kommentteja. (Tässä yksinkertaisessa esimerkkitapauksessa niitä ei tarvittaisi oikeasti.)

Tilanne korjataan antamalla testille hyv nimi. Hyvässä testin nimessä kuvaillaan järjestelmän alkutila, syöte ja odotettu lopputulos riittävällä tarkkuudella. Alla on esimerkki Given-When-Then-tyylistä.

TEST(ClientManagerTests, givenClientManagerWithMaxClients_whenClientAmountIsSetTo2_thenNewValueIsGotten)
{
    ClientManager myClientManager;
    const int maximumClientAmount = 10;
    myClientManager.setClientAmount(maximumClientAmount);

    const int newClientAmount = 2;
    myClientManager.setClientAmount(newClientAmount);

    CHECK(newClientAmount == myClientManager.getClientAmount());
}

Huonona puolena testin nimestä tulee pitkä, mutta toisaalta testiraportti kertoo tyhjentävästi, mikä on mennyt pieleen.

Failure in TEST(ClientManagerTests, givenClientManagerWithMaxClients_whenClientAmountIsSetTo2_thenNewValueIsGotten)
        expected <2>
        but was  <10>

Hyvä nimeämiskäytäntö

Jokaisessa testissä on kolme osaa.

  1. Alkutilaan asetus: Aluksi luodaan alkutilassa oleva testattava järjestelmä, esimerkiksi luodaan jokin olio määrätyillä parametreilla.
  2. Virike: Toisena syötetään järjestelmään jokin virike, esimerkiksi kutsutaan olion jotakin funktiota määrätyillä parametreilla.
  3. Lopputilan tarkastus: Lopuksi tarkastetaan, että järjestelmä on reagoinut odotetulla tavalla ja on päädytty haluttuun lopputulokseen.

Englanniksi näille vaiheille on useita nimityksiä mm. precondition-execution-postcondition, arrange-act-assert, require-do-ensure, given-when-then.

Given-when-then on siitä hyvä tyyli, että sillä kirjoitettuna testin nimi on lauseen muodossa. Se myös muistuttaa logiikassa ja matematiikassa käytettyä päättelykaavaa, joka suomeksi menee yleensä näin: Olkoon A suurempi kuin B, jos B on suurempi kuin C, niin A on suurempi kuin C. Testin nimessä ei kuitenkaan pitäisi jossitella, vaan aina testataan määrätty tapaus, joten nimeämiskaava olisi suomeksi olkoon–kun–niin.

Given-when-then -tyyli muistuttaa myös käyttötapauskertomuksen (user story) kaavaa, joka menee näin: As a client manager with 10 clients, I want to be able to change the amount of clients, so that I know the current client amount. Selvästikin Given... when... then... on toinen tapa muotoilla As a... I want... so that. Edellistä käytetään testeissä ja jälkimmäistä ohjelmiston määrittelyssä (speksauksessa).

Tämä johtaa siihen oivallukseen, että periaatteessa speksi = testi ja testi = speksi. Ihanteellisessa tilanteessa ohjelmistolla ei olisi eri tasoisten testien lisäksi mitään muuta määrittelydokumentaatiota.

torstai, 19. syyskuu 2013

Tietoa tästä blogista lyhyesti

Terve!

Tämä on tietokoneohjelmointiin ja ohjelmistokehitykseen liittyvä blogi. Kirjoittaja on ohjelmoinnin ammattilainen, joka on työskennellyt ohjelmoijana, testaajana, määrittelijänä (eli speksaajana), scrum masterina ja ohjelmointivalmentajana.

Blogin nimi, Koodiniekka, sai innoituksensa Reija Härkösen kirjoituksesta Virkamiehestä virkaniekka (http://reijaharkonen.vapaavuoro.uusisuomi.fi/kulttuuri/137377-virkamiehesta-virkaniekka), jossa ehdotetaan niekka-päätteen käyttämistä mies-päätteisissä ammatti- ja virkanimityksissä. Kannatettava ajatus. Koodi tarkoittaa tietysti ohjelmakoodia. Siis koodiniekka on suunnilleen sama kuin ohjelmoija eli koodaaja.