Veikkaan, että olet joskus kuullut jonkun kollegan suusta lauseen “toimii se minun koneella ainakin”. Tätä lausetta et haluaisi kuulla, sillä sitä käytetään yleensä sellaisessa tilanteessa, jossa jokin tietojärjestelmä tai työkalu ei toimi, eikä kukaan oikeastaan tiedä miksi.

Testaus ei todellakaan ole aina helppoa ja siksi on olemassa yrityksiä, jotka ovat erikoistuneet pelkästään siihen. Erityisen hankalaa IT-maailmassa on useamman eri järjestelmän välisten asioiden tarkastelu. Tästä puhutaan tyypillisesti “end-to-end”-testauksena.

Tässä asetelmassa on kyse siitä, että yksi järjestelmä tuottaa informaatiota, jota jokin toinen järjestelmä vastaanottaa ja muokkaa. Tämän jälkeen informaatio lähetetään vielä syötteeksi kolmanteen järjestelmään.

Avaan tätä yksinkertaistetun kuvan kautta.

Tilanne on siis yllä olevan kuvan mukainen. Ensimmäinen kohta (vasemmassa reunassa) on helppo testata. Tuotat järjestelmään tietoa ja katsot, että se näyttää oikealta. Myös viimeinen kohta (oikeassa reunassa) on helppo testata.

Vastaanotat tietoa ja jos se on syötetty järjestelmään oikein, näyttää se edelleen samalta. Keskimmäinen kohta tuottaa eniten haasteita, vaikka tässä kuvassa se näyttääkin yksinkertaiselta.

Avataanpa näitä haasteita nyt esimerkin kautta hieman syvällisemmin. Kuvitellaan yksinkertainen kone. Kone vastaanottaa numeron ja tallentaa tiedon ”0”, jos luku on parillinen ja tiedon ”1”, jos luku on pariton.

Tämän toimivuuden voi testata helposti. Ilmiselvin testaustapa on syöttää koneelle luvut 1-10 ja katsoa, onko jakauma nollien ja ykkösten välillä 50/50. Vielä tässä vaiheessa testaaminen vaikuttaa suoraviivaiselta ja selkeältä. On jopa vaikea käsittää, mikä voisi mennä pieleen. Todellisuudessa yksinkertaisimmatkaan asiat eivät aina ole niin yksinkertaisia kuin miltä ne äkkiseltään vaikuttavat.

Testiympäristöjä on monenlaisia

Hypätään tässä vaiheessa hieman ympäristöasioihin. Järjestelmämaailmassa puhutaan kahdenlaisesta ympäristöstä: tuotantoympäristöstä ja testiympäristöstä.

Tuotantoympäristössä ei tyypillisesti haluta testata mitään. Siksi on olemassa erillinen testiympäristö, jossa kaikki voidaan jopa rikkoa huoletta. Testiympäristöjäkin voi itse asiassa olla kaksi, joista yksi on kehittäjille ja toinen loppukäyttäjille tarkoitettu.

Tämä riittää silloin, kun testataan vain yhtä järjestelmää. Nyt kun siirrytään testaamaan “end-to-end” -prosessia, koko prosessista pitäisi olla saatavilla testiympäristöt ja vieläpä linkitettyinä toisiinsa. Esimerkkitapauksessa meidän pitää muokata vasemman järjestelmän tietoja ja tarkastaa toimivuutta oikealla olevassa järjestelmässä.

Kun testausta siis suunnitellaan, pitää muistaa toteuttaa tarpeeksi myös “end-to-end” -testiputkia, jolloin asioita voidaan testata riittävän kattavasti.

Ihanteellinen järjestelmärakenne tekstimme esimerkissä olisi seuraavanlainen:

Tällaisella rakenteella kehittäjät voivat testata omassa ympäristössään ilman yhteyksiä toisiin järjestelmiin. Toimittaja voi testata vähän korkeammalla tasolla omassa testissään, tyypillisesti yhteydet ovat yhdensuuntaiset tai jos mahdollista muista järjestelmistä on myös 3 instanssia (kustannussyistä tätä monesti ei haluta).

Tämän asetelman mukaista järjestelmien kokonaisuutta ei monesti ole valmiina, vaan se tulee toteuttaa esimerkiksi osana järjestelmän 2 toimitusta. Tämä vaatii aikaa tyypillisesti useammalta osapuolelta, sillä ei ole mitenkään epätavallista, että kaikki kolme järjestelmää ovat eri toimittajien tekemiä ja infrastruktuuri järjestelmien välillä on IT-osaston hallinnoima kokonaisuus.

Haluatko tietää, kuinka tilaajan kannattaisi ohjelmistotestaukseen suhtautua? Lue tuore haastattelu aiheesta.

Suunnittelupöytään siis tarvitaan helposti 3-4 eri osapuolta, jotta kokonaisuus saadaan toimimaan. Lienee selvää, että tähän tulee varata riittävästi aikaa.

Exception, exception, exception – millä nämä vikailmoitukset oikein saa loppumaan?

Nyt kun meillä on käsitys hyvästä järjestelmien rakenteesta, voimme palata kakkosjärjestelmän testaamiseen.  Järjestelmä on helppo todeta toimivaksi luvuilla 1-10. Luodaan luvut ykkösjärjestelmään ja todetaan, että informaatio on kirjautunut järjestelmään oikein.

Vielä muistutuksena: järjestelmä yksi luo siis lukuja, järjestelmä kaksi tallentaa tiedon lukujen parillisuudesta / parittomuudesta sekä järjestelmä kolme tulostaa tiedon PDF-tiedostoon. Kolmosjärjestelmä liittyy tyypillisesti johonkin loppuasiakkaan tulosteeseen, jolloin se saa eniten huomiota.

Kaiken pitäisi nyt toimia ongelmitta. Testaamme tulostusta. Testaus keskeytyy virheilmoitukseen “Exception…”, joka tarkoittaa ohjelmointikielellä virhettä. 

”Testaus keskeytyy virheilmoitukseen “Exception…”, joka tarkoittaa ohjelmointikielellä virhettä.”

Unohdimme kakkosjärjestelmän testauksessa tyhjät arvot. Tyhjä kun ei ole parillinen eikä pariton (koodi tälle on kutakuinkin muotoa i % 2 == 0, jossa i on syötetty luku ja jos lukua ei ole alustettu, sen arvo on “null” joka aiheuttaa virheen).

Löysimme siis järjestelmästä bugin. Lisätään käsittelyä näille ja jatketaan. Tällä kertaa ykkösjärjestelmään syötetään luku 2.0. Jälleen tuloksena on vikailmoitus.

Tällä kertaa kyseessä onkin väärä lukumuutos, koska aikaisemmassa vaiheessa oletettiin, että kakkosjärjestelmä saisi syötteenä vain kokonaislukuja. Lisätään käsittely sille, että koodin voi ajaa muillakin kuin kokonaisluvuilla.

Muutosten jälkeen olemme tyytyväisiä, kun saamme luvuille 2.0, 3.0 ja 4,5 oikeat arvot paperille. Hienoa. Voimme vihdoin edetä tuotantoon.

Ei muuta kuin tuotantoon – eikun ei sittenkään

Tuotannossa ensimmäinen käyttäjä syöttää ensimmäiseen järjestelmään luvun PII parhaan mahdollisen likiarvon – ja taas tuloksena virheilmoitus. Seuraava käyttää niin isoa lukua, että järjestelmän numeroavaruus ei riitä – lopputuloksen arvaattekin jo.

Tässä vaiheessa syyttömien rankaiseminen on todennäköisesti jo täydessä vauhdissa. Todellisuudessa olisi pitänyt tarkemmin määritellä, mitä lukuja voidaan ottaa vastaan sekä ilmoittaa ensimmäiselle järjestelmälle, mikäli syötteenä koitetaan antaa lukua, joka ei täytä vaatimuksia. Tällöin järjestelmä voidaan opastaa ohjeistamaan käyttäjää oikeanlaisten lukujen syöttämisessä. Nämä asiat ovat kaiken kiireen keskellä jääneet huomaamatta.

Mitkä ovat olleet urani ikimuistoisimmat IT-projektit? Tutustu haastatteluun, jossa kävin läpi ikimuistoisimpia projekteja sekä niistä saatuja tärkeimpiä oppeja.

“End-to-end -testaaminen on erittäin kannattavaa.”

“End-to-end” -testaaminen on siis erittäin kannattavaa – ja samalla sen suunnitteleminen on erittäin haastavaa. Jos kakkosjärjestelmä rakennetaan tyhjiössä, on suuri todennäköisyys epäonnistua.

Kuvien mukaisen testijärjestelyn suunnittelu, toteutus ja testien läpivienti vie kuitenkin aikaa. Aikaa, jota ei välttämättä ole budjetoitu toisen järjestelmän toteuttamiseen tarkoitetulle projektille.

Tällöin nipistetään herkästi testiympäristöjen määrästä ja todetaan, että ”kyllä se riittää”. Tämä on kuitenkin testauksen se vaihe, jolloin viimeistään virheet pitäisi löytää. Muuten virheen korjauksen kustannus kasvaa usein moninkertaiseksi.

Tällöin ei pelkästään korjata virhettä, vaan mahdollisesti joudutaan korjaamaan lisäksi myös tuotannon dataa, joka on mennyt vinksalleen huomaamatta jääneen virheen takia.

Toinen seikka, johon on myös syytä kiinnittää huomiota on testidatan laatu.

Jostain joukko-opin oppitunneilta saatamme muistaa, että luvut voidaan jakaa osiin ja mikäli vaatimus on, että ohjelma toimii kaikilla luvuilla, meidän pitää osata valikoida testidataa kaikista lukujen osajoukoista.

Data tulee aina olemaan osajoukko, sillä testaaminen kaikilla luvuilla vie liikaa aikaa. Testaus tukeutuu pitkälti todennäköisyyslaskentaan, jonka avulla virheen todennäköisyys pienennetään riittävällä otannalla hyväksyttävälle tasolle.

Lause “toimii ainakin minun koneellani” on jotain, jonka varmasti tulemme vielä joskus kuulemaan, mutta hyvällä suunnittelulla ja testidatan valinnoilla voimme kuitenkin pienentää sen todennäköisyyttä merkittävästi.