Tacsiazuma
Tacsiazuma A letscode.hu alapitója, több, mint egy évtized fejlesztői tapasztalattal. Neovim függő hobbi pilóta.

Unit test meg amit akartok

A szoftverek tesztelésének több fajtája van, amik közül néhányról azok is hallhattak már, akik igazából nem foglalkoznak fejlesztéssel ( Ilyen például a béta-tesztelés). Ellenben van egy tesztelési forma, ami szoros kapcsolatban áll a konkrét fejlesztéssel és végigköveti annak életciklusát.

Ez pedig a unit testing.

Mi az a Unit?

Unit testing esetében a unit ( magyarul egység) az a legkisebb darabja a programnak, ami valami konkrét feladatot lát el. Esetünkben ez egy függvény/metódus. Minden egyes teszt egy ilyen kis darab működését (visszatérési érték, dobott kivételek) teszteli le különböző körülmények (paraméterek, stb.) között. Unit testing során függetleníteni kell a többi, külső tényezőtől a tesztelni kívánt részletünket, ezért használunk ún. mock object-eket és hasonlókat, de erről majd később.

Assert

A programozási nyelvek többségében szerepel egy assert névvel (vagy éppen funkcióval) bíró függvény.

1
2
assert(TRUE);
assert(1==1);

Ezt leginkább egy if - else elágazáshoz lehetne hasonlítani, azzal az eltéréssel, hogyha itt logikai vizsgálat false-al zárul, akkor a bulinak annyi, a kódunk nem fog tovább menni. Ugyanis itt nem vizsgáljuk a dolgot, hanem kijelentünk valamit, aminek úgy kell lennie.

Unit tesztelés során a különböző egységeket ilyen módon vizsgáljuk, az egyes nyelvekre specifikus unit testing framework-ök segítségével (persze mi is összeügyeskedhetünk valami egyszerűbbet ). Php esetében ilyen lehet például a PHPUnit, Javascript esetében pedig a QUnit. Ezeknek az installálásra nem térnék ki részletesebben, elég jól leírják a honlapjukon, inkább nézzünk egy tesztelni kívánt osztályt/metódust és egy arra írt tesztet.

1
2
3
4
5
6
7
8
 <?php

class ClassToBeTested {
     
     public function MeaningOfLife() { // ügyeljünk arra, hogy csak publikus függvényeket tudunk meghívni
          return 42;  
     }
}

Rémegyszerű a képlet, van egy osztályunk, azon belül van egy publikus metódusunk, ami nem vár paramétert és 42-t ad vissza. Nézzünk rá egy tesztet:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php

use PHPUnit_Framework_TestCase as TestCase; // a PHPUnit tesztesetét használjuk fel

class OurFirstTest extends TestCase { // és abból származtatjuk a tesztünket

        private $classToBeTested; //  

        public function setUp() { // ezt a metódust meghívja a PHPUnit a tesztek előtt
              $this->classToBeTested = new ClassToBeTested(); // az autoloaderek segítségével a ClassToBeTested.php fájlban fogja ezt keresni a framework
        }
        
        public function TestMeaningOfLife() {  
              $meaningOfLife = $this->classToBeTested->MeaningOfLife();
              $this->assertEquals(42,$meaningOfLife); // azt ellenőrzi, hogy a két paraméter egyenlő-e (csak '==', nem '===' !)
        }
}

A fenti kód a következőket csinálja, példányosítja az imént definiált osztályunkat, meghívja a MeaningOfLife metódusát és a visszatérési értéket pedig összeveti 42-vel. Mivel az 42 lesz, ezért a tesztünk sikeres. Persze ez egy nagyon lebutított példa, hiszen nem ennyi logika rejtezik 1-1 függvény mélyén.

TDD

A TDD rövidítés a Test-Driven Development fogalmat takarja, ami a szoftverfejlesztés egyik “műfaja”. A lényegét egy képpel lehetne ábrázolni:redgreenrefacor

A folyamat alapvetően három stádiumból áll, amiket a fejlesztés során ismétlünk. Red-> Green -> Refactor.

Mi a … az a Red?

A red esetünkben a failing testre utal, ugyanis a unit teszteléskor a legtöbb keretrendszer valamiféle vizuális módon megjeleníti az eredményt és sikertelenség esetén pirossal jelöli azt. Ebből következik, hogy a zöld a sikeres teszt, a refaktorálást pedig akinek kell, annak nem most fogom elmagyarázni 🙂

De miért sikertelen teszttel kezdünk?

A dolog roppant egyszerű és ebben rejlik a lényeg. TDD esetén a tesztek irányítják a programozás folyamatát. Írunk egy egyszerű, egy igazán egyszerű tesztet. Mivel semmi nincs mögötte, nincs kész az osztály, amit tesztelünk, ezért a teszt sikertelen lesz (már ha egyáltalán lefut). Ez a red.

Ezután megnyitjuk a programunkat és elkészítjük az adott osztályt, és a hozzá tartozó metódust úgy, hogy az a tesztet kielégítse. Lefuttatjuk újra a tesztet… siker. Green.

Ezután pedig végignyálazzuk a kódunkat, ismétlődésekre vadászva, hiszen ahol ismétlődés van, ott lapul egy “minta”, ott valamit össze lehet vonni, stb. Refactor.

A folytatásban végigvesszük a folyamatot és írunk TDD-módra egy római szám -> arab szám konvertáló programot.

comments powered by Disqus