Behavior Driven Development ja Cucumber ehk ilusam tarkvara valutu(ma)lt

Sissejuhatuse asemel

Kõik sai alguse sellest, kui ühel ilusal päeval rändasin Suurbritanniasse ja sattusin poolkogemata tööle pisikesse startupi nimega Picklive. Seal kasutati minu jaoks tol hetkel (ja tänaseni) väga uudseid ja põnevaid vahendeid lisaks juba tuntud asjadele – Ruby on Rails, XMPP, JavaScript, agiilne metoodika jne. Alustasin ka seal tegelikult testimisest, aga üsna pea selgus, et sellest jääb väheks. Seega asusin tasapisi ka parandama vigu, mis leidsin. Märkamatult kirjutasin juba lisaks päris uut funktsionaalsust.

Mis tegelikult mu mõtteviisi tarkvara arendamise ja testimise kohta muutis, oli hetk, kui otsustasime võtta kasutusele Behavior-Driven Development (BDD) metoodika ning selle elluviimise vahendiks sai valitud Cucumber. Kuigi BDD’d saab defineerida mitmeti, on minu arust pädevaim Dan North’i antud kirjeldus:

BDD is a second-generation, outside–in, pull-based, multiple-stakeholder, multiple-scale, high-automation, agile methodology. It describes a cycle of interactions with well-defined outputs, resulting in the delivery of working, tested software that matters.

BDD definitsiooni järgi tekib tarkvara väljast sisse – esmalt defineeritakse tulemus, mida soovime saavutada, seejärel kirjeldatakse käitumine, mis meid soovitud tulemuseni viib ja alles siis kirjutatakse tegelik programmikood, mis teeb seda, mida me tahame, et ta teeks. Tulemuse definitsioon ja käitumise kirjeldused on esitatud inimloetava tekstina.

BDD ei ole vaid metoodika, see on käsitletav ka mõtteviisina. Meie töö eesmärgiks on luua tarkvara, millest tekib tulu kõigile. Iga planeeritava funktsionaalsuse juures tuleks mõelda, kas see aitab meil (ettevõttel) saada rohkem tulu? Kas see aitab meid kui ettevõtet kuidagi esile tõusta? Kas meie tarkvara kasutajad saavad sellest kuidagi kasu? Kui ei, siis üsna tõenäoliselt ei ole tegu väga vajaliku või kasuliku funktsiooniga. Selle võib seega kas hetkel kõrvale lükata või siis üldse välja jätta.

Samuti lubab BDD metoodika arendajal keskenduda küsimusele, miks üht või teist funktsionaalsust vaja on, mitte vaid sellele, kuidas seda teostada või kuidas üht või teist tehnilist probleemi lahendada.

Nagu enamus agiilseid metoodikaid, on BDD puhul kasutatud lähenemised, mis lihtsustavad arendaja elu ja parandavad koodi kvaliteeti:

  • YAGNI (You Ain’t Gonna Need It) – kood kirjutatakse alles siis, kui seda reaalselt vaja on, mitte kunagi „igaks juhuks“. Sellega välditakse koodis liiasusi (code bloat) ning hoitakse kood puhas ja kergesti hooldatav.
  • DRY (Don’t Repeat Yourself) – kui sama koodilõiku kasutatakse rohkem kui ühes-kahes kohas, on mõistlik see koodilõik eraldi funktsioonina esitada (Single Source of Truth).
  • Red-Green-Refactor – koosta testid, mis feilivad, kirjuta koodi, kuni testid passivad, refaktoori ning korda kogu tsüklit algusest. Tulemuseks on loodetavasti parem ja kvaliteetsem kood, mis endiselt teeb seda, mis vaja.

 

Cucumber ja Gherkin ehk miks aedviljad nii olulised on

Olles rääkinud sellest, mis on BDD ja korraks maininud ka Cucumberi nimelist vahendit, olekski siinkohal õige hetk lühidalt rääkida sellest, mis see Cucumber selline on.

Cucumber on raamistik, mis võimaldab inimloetava tekstina esitada tarkvara käitumise kirjelduse. See moodustab üheaegselt nii dokumentatsiooni, spetsifikatsiooni kui ka automaattestid. Seepärast nimetatakse selliseid kirjeldusi käivitatavaks spetsifikatsiooniks (executable specification).

Cucumber on kirjutatud Ruby’s ja sobib kõige paremini Ruby koodi testimiseks, kuid on üsna kergesti kasutatav muudes keeltes loodud või loodava tarkvara juures, sealhulgas Java, C#, Python jpt. On olemas mitmeid Cucumberi porte, neist olulisemad ehk:

  • Cucumber-JVM – puhtalt Javas kirjutatud port, mis toetab selliseid programmeerimiskeeli nagu Java, Groovy, Scala, Clojure, JavaScript (Rhino interpretaatori abil), Python (Jython interpretaator) ning Ruby (JRuby interpretaator).
  • Cucumber.js – Javascripti implementatsioon, mis suudab teste jooksutada otse brauseris.
  • SpecFlow – implementatsioon .NET jaoks.

Mingil põhjusel on aedviljad agiilsete vahendite loojatele südamelähedased, seega kannab Cucumberi kasutatav keel nime Gherkin ehk väike marineeritud kurk. Gherkin on äriloetav valdkonnaspetsiifiline keel (business-readable domain specific language), mis võimaldab kirjeldada tarkvara käitumist ilma laskumata detailidesse (kuidas käitumine saavutatud on). Kirjeldused on üles ehitatud lugudena, kõige kõrgem ning üldisem tase on feature ehk funktsionaalsus, mida me luua soovime. Iga feature on omakorda kirjeldatud täpsemalt ühe või enama stsenaariumi (scenario) abil. Näide, kuidas Gherkinis kirjeldada väga lihtsa programmi – kalkulaatori, mis oskab vaid kahte arvu liita – käitumist, võiks olla järgmine:

Feature: Addition
   In order to avoid silly mistakes
   As a math idiot
   I want to be told the sum of two numbers

   Scenario: Add two numbers
     Given I have entered 50 into the calculator
     And I have entered 70 into the calculator
     When I press add
     Then the result should be 120 on the screen

Nagu näeme, on see kirjeldus üheselt mõistetav ning kergesti loetav nii programmeerijale, testijale, analüütikule, turundusinimesele, kliendile kui firmajuhile. Samuti on Gherkin kasutatav enam kui neljakümnes erinevas keeles (kaasa arvatud eesti keeles).

Kuid ainult kirjeldusest, kuidas meie loodav rakendus peaks käituma, ei piisa – rakendus tuleb ka valmis kirjutada nii, et ta meie ootusi täidaks. Ka siin tuleb meile appi Cucumber, mis võimaldab eeltoodud kujul kirjeldusi käivitada kui automaatteste ning annab meile vihjeid, mida peaks edasi tegema.

Luues päris uut funktsionaalsust, on suure tõenäosusega meie stsenaariumide sammud defineerimata – me küll kirjeldame käitumist sammhaaval, aga Cucumber ei tea, mida me nende sammudega silmas peame. Et Cucumber meie stsenaariumidega midagi teha oskaks, peame sammud defineerima – kirjutama koodi, mis vastava sammu kohtamisel käivitatakse. Peale sammude defineerimist uuesti Cucumberit käivitades saame juba tõenäoliselt veateate – meie samm on küll defineeritud, aga reaalset rakenduse koodi, mida definitsioonikood välja kutsub, ei ole veel olemas.

Seega järgmise sammuna kirjutamegi juba rakenduse koodi, kuni meie sammudefinitsioon annab positiivse tulemuse, ning liigume edasi järgmise sammu juurde. Nii tekibki rakendus väljast sisse – alustame kõige üldisemast kirjeldusest ja lõpetame detailidega rakenduse koodis.

Lisaks kirjeldatud “väljast-sisse” metoodikale rakenduse loomisel kasutatakse sarnast, “alt-üles” põhimõtet ka väiksemas mõõtkavas – Cucumberi stsenaariumide kirjutamisel:

  • Kuna tulemus on meile kõige olulisem, seega esmalt kirjeldame, mida me saada tahame – koostame Then sammud.
  • Oodatud tulemuseni jõudmiseks peame sooritama mingeid tegevusi, seega järgmisena kirjeldamegi need – koostame When sammud.
  • Lõpuks, kui me teame, mida me tahame ja oleme välja mõelnud, kuidas me selle tulemuseni võiksime jõuda, saame koostada piisavad eeldused meie stsenaariumi mõtestamiseks – koostame Given sammud.

 

QA roll BDD tiimis

Kuigi siiani olen rääkinud BDD metoodikast rohkem arendajate poolelt ja testimist vaid möödaminnes maininud, siis ei tähenda see, et testijatel sellises stiilis töötavates tiimides kohta ei ole. Kuigi by definition on BDD metoodikat järgides loodud kood alati 100% ulatuses testidega kaetud (eeldusel, et arendajad järgivad BDD metoodikat rangelt), ei tähenda 100% kaetus veel 100% testitust. Meie käitumise kirjeldused ei pruugi katta äärejuhtumeid, rääkimata erijuhtumitest kategoorias “selle peale me ei osanud mõeldagi”. Iga lisapaar silmi, kes koodi ja toodet üle vaatab, on lisakindlustuseks toote kvaliteedile ning testija kaasamine aitab vältida olukordi, kus meie 100% testidega katvust pakkuva moodsa arendusmetoodika põhjal kirjutatud rakendus võib piinlikult triviaalsetes olukordades katkiseks osutuda.

Samas testija BDD tiimis ei peaks olema ainult testija, vähemasti mitte klassikalises mõttes. Täiesti vabalt võib (ja tegelikult isegi peaks) sellises keskkonnas töötav testija olema piisavalt pädev kirjutama rakenduse uute funktsioonide kirjeldusi nii feature kui scenario tasemel, koostama stsenaariume erijuhtude katteks ning neid sammudefinitsioonidega varustama, ideaaljuhul suutma ka rakenduse koodi sisse viia lihtsamaid parandusi ja täiendusi.

 

CukeUp! 2012

Kuna tegelikult ajendas seda postitust kirjutama hoopis aprilli alguses külastatud konverents CukeUp! 2012 Londonis, siis mõne sõnaga ka seal kuuldust. Põhilised teemad keerlesid Cucumberi ümber, räägiti selle erinevatest portidest (Cucumber-JVM, Cucumber.js), sellest, kuidas Cucumberi variatsioon Calabash võimaldab testida mobiilseid rakendusi otse seadmel ja kuidas rakendada BDD mõtteviisi embedded riistvara disainimisel jpm.

Isiklikult jäi rohkem meelde Colin Humphreys’i loeng teemal, kuidas testida mitte ainult stsenaariumidega kirjeldatud tarkvara käitumist, vaid ka seda, kas meie stsenaariumid ja featuurid täidavad nende kirjelduses püstitatud ärieesmärke. Samuti jäi kõrva Chris Roff’i loeng Cucumberi kirjelduste kogumi kui elava dokumentatsiooni teemal. Lisaks rääkis Elizabeth Keogh väga köitvalt teemal: mida teha siis, kui meie oodatavad tulemused ei olegi väga täpselt määratletud, ja kas häguste eesmärkide puhul on endiselt võimalik testimist automatiseerida.

Natuke teistlaadi teemana oli väga põnev kuulata Karl Krukow’i loengut Calabashist – Cucumberi variandist, mis on mõeldud mobiilirakenduste testimiseks otse füüsilisel seadmel või emulaatoris. Calabash on kasutatav nii iOS kui Android seadmetel, lisaks pakutakse ka pilves elavat testimise teenust nimega LessPainful, mis võimaldab arendajatel oma koodi testida erinevatel seadmetel, mis on kõik füüsiliselt olemas, mitte emuleeritud. Seejuures testida saab mitte ainult ekraanil toimuvat, vaid on võimalik kasutada ka näiteks kaamerat, GPS’i, füüsiliselt seadet keerata (seadmed on paigutatud paneelile, kus servomootorid neid füüsiliselt keeravad, videodemonstratsioon antud võimalusest tekitas kuulajates korralikku elevust) jne.

Päeva lõpetas diskussioon teemal, kuhu Cucumber edasi liikuda võiks, millised võimalused peaks kaotama, millised lisama. Diskussioonis osalesid Matt Wynne, Aslak Hellesoy, Oriol Gual, Julien Biezemans ning Jonas Nicklas, kes kõik on püüdnud Cucumberit viia uutesse suundadesse (Cucumber-JVM, Spinach, Turnip, TextMapper) ja püüdsid üheskoos tuua igaühe head kokku Cucumberisse ning anda ülevaade tehtud vigadest ja neist õpitust.

Kuna räägiti palju ja erinevatel teemadel, ning kõiki loenguid nende paralleelselt toimumise tõttu ei jõudnud isiklikult külastada, siis kogu asjast lõpliku ülevaate saamiseks kulub ka minul veel natuke aega. Huvilistel on võimalik kõiki loenguid koos slaididega videos jälgida siin.

Leave a Reply

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