←back to Blog

13 ohjelmistotestauksen anti-patternia — tunnistatko nämä omassa projektissasi?

Yksikkötestit ilman integraatiotestejä, testikoodin kohteleminen kakkosluokan kansalaisena, satunnaisesti feilaavat testit… Tunnistatko näitä ongelmia omassa projektissasi? Kostis Kapelonis kokosi vuonna 2018 kattavan listan 13 testauksen anti-patternista, ja ne ovat hämmentävän ajankohtaisia vielä tänäänkin.

Törmäsin hiljattain Hacker Newsin kautta erinomaiseen Codepipes-blogin artikkeliin Software Testing Anti-patterns. Vaikka artikkeli on vuodelta 2018, sen listaamat ongelmat ovat edelleen arkipäivää suomalaisessakin ohjelmistokehityksessä. Käydään läpi keskeisimmät opit ja peilataan niitä pohjoismaiseen testauskulttuuriin.

Mikä on testauksen anti-pattern?

Anti-patternilla tarkoitetaan toistuvaa ratkaisumallia, joka näyttää päällisin puolin järkevältä mutta johtaa käytännössä huonoihin lopputuloksiin. Testauksen kontekstissa tämä tarkoittaa tapoja kirjoittaa, ajaa ja ylläpitää testejä, jotka ennemmin tai myöhemmin kostautuvat — joko hukattuna aikana, valheellisena turvallisuudentunteena tai koko testauskulttuurin romahtamisena.

Kapelonis listaa peräti 13 eri anti-patternia, jotka kattavat kaiken yksikkö- ja integraatiotestien epätasapainosta aina TDD-fundamentalismiin ja testikoodin laiminlyöntiin. Tässä niistä tärkeimmät suomalaisen testausammattilaisen näkökulmasta.

Yksikkötestit vs. integraatiotestit — ikuisuuskysymys

Kaksi ensimmäistä anti-patternia osuvat suoraan ikuisuuskeskustelun ytimeen: pelkät yksikkötestit ilman integraatiotestejä, ja päinvastoin. Kumpikin on yleinen ansa, mutta eri syistä.

Pelkkiin yksikkötesteihin sortuvat usein pienemmät talot, joissa senioriosaamista ei ole riittävästi. Yksikkötestit on helppo kirjoittaa ja ne toimivat nopeasti, mutta ne eivät koskaan paljasta tietokantatriggereiden, transaktioiden tai rajapintasopimusten rikkoutumista. Integraatiotestien puuttuminen on kuin testaisi auton moottoria pelkällä kuuntelulla — käyntiääni voi olla hyvä, mutta vaihteet eivät mene päälle.

Toisessa ääripäässä isot yritysprojektit saattavat luottaa pelkkiin integraatiotesteihin. Kapelonis näyttää vakuuttavasti matematiikan: jos yhdessä palvelussa on neljä moduulia joiden koodipolut ovat 2, 5, 3 ja 2, tarvitaan 60 integraatiotestiä kattamaan kaikki kombinaatiot. Yksikkötesteillä sama hoituu 12 testillä. Ja nuo 60 integraatiotestiä vievät minuutteja, kun 12 yksikkötestiä vie sekunteja.

Älä testaa implementaatiota — testaa käyttäytymistä

Tämä on mielestäni koko artikkelin tärkein yksittäinen oivallus. Liian usein näkee testejä, jotka on kirjoitettu tarkistamaan, että jokin tietty kenttä on tietyssä oliossa tietyllä arvolla. Kun bisnesvaatimukset muuttuvat — ja nehän muuttuvat — kaikki nämä testit hajoavat kerralla.

Oikea tapa on testata mitä järjestelmä tekee, ei miten se sen tekee. Jos testaat vaikkapa asiakkaan rekisteröitymistä, älä tarkista, onko customer.type === 1. Testaa sen sijaan, että rekisteröitynyt asiakas saa alennuskoodin tai pääsee käsiksi premium-sisältöön. Kun sisäinen toteutus muuttuu, testit pysyvät ehjinä — ja se on koko automaatiotestauksen idea.

Koodikattavuus on harhaanjohtava mittari

Kapelonis lyö tiskiin rohkean väitteen: koodikattavuus on täysin hyödytön metriikka. Hän perustelee tätä Codepipes Testing Metrics (CTM) -mallillaan, jossa oikeasti tärkeitä mittareita ovat:

  • PDWT — kuinka moni kehittäjä kirjoittaa testejä (tavoitearvo: 100 %)
  • PBCNT — kuinka moni tuotantobugi johtaa uuteen testiin (tavoitearvo: 100 %)
  • PTVB — kuinka moni testi testaa käyttäytymistä eikä implementaatiota (tavoitearvo: 100 %)
  • PTD — kuinka moni testi on deterministinen eli ei satunnaisesti feilaava (tavoitearvo: 100 %)

Suomalaisessa testauskeskustelussa koodikattavuus nostetaan edelleen liian usein jonkinlaiseksi laadun takeeksi. Olen nähnyt projekteja, joissa 85 % koodikattavuus on määritelty Definition of Doneen, mutta kukaan ei ole pysähtynyt miettimään, testataanko sillä 85 %:lla mitään oikeasti kriittistä. Kapeloniksen 20 % -peukalosääntö — testaa se 20 % koodista joka aiheuttaa 80 % bugeista — on paljon fiksumpi lähtökohta.

Flaky-testit tuhoavat koko testauskulttuurin

Tämä anti-pattern on erityisen tuttu jokaiselle, joka on työskennellyt CI-putkien kanssa. Jo viisi satunnaisesti feilaavaa testiä riittää syövyttämään kehittäjien luottamuksen koko testisuiteen. Kun buildi on punainen, kukaan ei enää tiedä, onko kyseessä oikea regressio vai taas yksi “se yleensä menee läpi kun ajaa uudestaan” -tapaus.

Flaky-testit syntyvät useimmiten integraatio- tai UI-testeissä, joissa ulkoiset riippuvuudet, ajoitusongelmat ja testiympäristön epävakaus nostavat päätään. Ratkaisu ei ole testien poistaminen, vaan niiden eristäminen omaan suiteensa ja juurisyiden järjestelmällinen korjaaminen.

TDD ei ole uskonto — eikä testien tarvitse aina tulla ensin

Kapelonis käsittelee TDD:tä (Test-Driven Development) rehellisen raikkaasti: se on hyvä työkalu, mutta siitä on tullut joillekin lähes uskonnollinen dogma. Startup-ympäristössä, jossa koodi elää ja hengittää nopeiden iteraatioiden tahdissa, testien kirjoittaminen jälkikäteen on täysin validi strategia. Olennaista on, että testit ylipäätään kirjoitetaan — ei se, missä järjestyksessä.

Suomessa TDD on yllättävän vahvasti edustettuna erityisesti konsulttivetoisissa projekteissa. Olen itse nähnyt tilanteita, joissa TDD-pakotus on hidastanut kehitystä enemmän kuin auttanut, koska kaikkea ei yksinkertaisesti kannata testata etukäteen. Kokeileva prototyyppaus ja testien kirjoittaminen vasta kun ratkaisu on selkiytynyt on monessa tapauksessa fiksumpaa.

Testikoodi on oikeaa koodia

Yksi artikkelin terävimmistä huomioista on, että testikoodia kohdellaan usein kakkosluokan kansalaisena. Testeissä kopioidaan ja liitetään surutta, kovakoodataan arvoja ja jätetään refaktorointi tekemättä — samoja syntejä, joista tuotantokoodissa saisi välittömästi huomautuksen koodikatselmoinnissa.

DRY, KISS ja SOLID pätevät yhtä lailla testikoodiin. Jos testien ylläpitäminen alkaa tuntua taakalta, vika ei yleensä ole testaamisessa itsessään vaan siinä, miten testit on kirjoitettu. Keskitetyt testidatan luontifunktiot, jaetut apumetodit ja staattisen analyysin ulottaminen testikoodiin ovat pieniä tekoja, joilla on iso vaikutus.

Mitä tästä voi oppia suomalaisessa testauskentässä?

Suomessa testausautomaatio on vakiinnuttanut asemansa erityisesti finanssi-, terveys- ja telekommunikaatioaloilla, mutta edelleen törmään projekteihin, joissa testauksen anti-patternit rehottavat. Erityisesti julkisen sektorin hankkeissa koodikattavuusprosentti saatetaan sopia etukäteen, mutta kukaan ei määrittele mitä sillä katetaan.

Toinen suomalainen erityispiirre on vahva konsulttivetoinen kehitysmalli, jossa testausvastuu sirpaloituu helposti. Kun kehittäjä, testaaja ja arkkitehti tulevat eri firmoista, kukaan ei välttämättä omista testistrategiaa kokonaisuutena. Tällöin anti-pattern numero 13 — “testauksen maineen pilaaminen tietämättömyydellä” — on erityisen suuri riski.

Yhteenveto

Kapeloniksen 13 anti-patternia muodostavat käytännössä tarkistuslistan, jonka jokaisen testausammattilaisen kannattaa käydä läpi oman projektinsa osalta. Kärjistetysti sanottuna: jos yksikin näistä osuu omaan tiimiin, testauksesta saatava hyöty on pienempi kuin siihen käytetty vaiva.

Omat kolme tärkeintä nostoani ovat: (1) testaa käyttäytymistä, älä implementaatiota, (2) unohda koodikattavuus tavoitteena ja keskity oikeasti kriittiseen koodiin, ja (3) kohtele testikoodia samalla ammattiylpeydellä kuin tuotantokoodia.

Mitä mieltä sinä olet? Tunnistatko näitä anti-patterneja omassa työssäsi? Jaa kokemuksesi kommenteissa!

Alkuperäinen artikkeli: Software Testing Anti-patterns — Kostis Kapelonis, Codepipes Blog (2018). Hacker News -keskustelu: 465 pistettä, 166 kommenttia.

Kuva: Daniil Komov / Pexels

Leave a Reply

Your email address will not be published. Required fields are marked *