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:
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.