Sokáig halogattam a PHP unit tesztekkel való megismerkedést. Így utólag kiderült, hogy egy rendkívül hasznos eszköz ami biztosabbá és fenntarthatóvá teszi a kódunkat. A cakephp eleve tartalmaz unit teszteléshez szükséges alkatrészeket, és a keretrendszer frissítésénél ütköztem egy rakat problémába ami unit tesztekkel könnyebben kezelhető lett volna.
Update: A végén azért összejött annyi érdekesség, hogy írtam az egészről egy e-bookot.
Nem fogok itt sem magukról a unit tesztekről írni, sem azokról a részletekről amik benne vannak egyértelműen a kézikönyvben. Itt csak azokra a hozzátevőkre térek ki amelyek kiderítése hosszadalmas volt.
Azt, hogy a test adatbázisban a cake_session táblát kézzel hozzá kell adni, még viszonylag gyorsan megtaláltam, de többit itt lent már nem.
Miután feltelepítettük a PHPunit-ot és létrehoztuk a test adatbázis kapcsolatot első körben létre kell hoznunk a fixture-öket. Persze ez le van írva a kézikönyvben, de ha az ember hajlamos egyből beleugrani akkor kellemetlen meglepetésekkel szembesülhet. Esetemben ez megmagyarázhatatlan átirányításokkal járt, míg végül rájöttem, hogy ha hirtelen a http://localhost címen találom magam akkor az app/tmp/logs/error.log file-t kell megnézni, mert ott lesz valami gubanc.
A másik meglepetés a controllerek tesztelésénél jött elő, ugyanis ha a $this->generate() hívásnál nem adjuk meg a components tömbben a DebugKit.Toolbar-t (már legalábbis ha egyébként használjuk), akkor szintén nehezen értelmezhető hibákba futkosunk majd bele.
A következő kihívás a Session válozók kezelése volt. Erre az a megoldás, hogy egyrészt megadjuk a $this->generate() hívás során a components tömbben a Session-t, hozzáadjuk a fixture tömbhöz a core.session-t, majd a következő kódot használjuk.
class BizonylatokControllerTest extends ControllerTestCase { public $fixtures = array('app.bizonylat', 'core.session'); public function setUp() { parent::setUp(); $this->Bizonylatok = $this->generate('Bizonylatok', array( 'components' => array('Session', 'DebugKit.Toolbar') ) ); } function testBizonylatokAkarmi(){ $this->controller->Session->expects($this->any()) #legalább egyszer ->method('read') #meghívjuk Session:read() metódust ->with($this->equalTo('Settings.cegId')) #és kiolvassuk belőle a 'Session.cegId' paramétert ->will($this->returnValue(2)); #akkor adjunk vissza visszatérési értékként 2-t }
A következő kihívás akkor jött amikor többféle session változót használt a tesztelt controller. Erre a returnCallback adott megoldást.
$this->controller->Session->expects($this->any()) ->method('read') ->with($this->logicalOr('Settings.cegId', 'Settings.ev')) ->will($this->returnCallback( function($param){ if($param == 'Settings.cegId') return 2; elseif($param == 'Settings.ev') return 2012; else return null; } ));
Majd a privát metódusok tesztelése jött a sorban.
$myClass = $this->generate('Bizonylatok'); $class = new ReflectionClass ($myClass); $method = $class->getMethod ('_szamFormal'); $method->setAccessible(true); $actual = $method->invoke($myClass, '5 000,25'); $expected = 5000.25; $this->assertEquals($expected, $actual);
Ami még tovább fokozta az izgalmaimat az az, hogy join táblákra habtm kapcsolat esetén hiába hoztam létre a fixture-t és adtam használatra egy model teszt esetében, folyamatosan arra panaszkodott, hogy nem létezik a tábla. Jópár órányi őrület után aludtam rá egyet és bekapcsoltam a MySQL szereren, hogy loggoljon minden egyes query-t. Ebből láttam, hogy a join táblát nem jól többesszámúsítja az inflector, mivel magyar táblaneveket használok. A megoldás az lett, hogy a /app/Config/bootstrap.php file-ban hozzá kellett adnom még egy egyedi többesszámos szabályt.
Inflector::rules('plural', array( 'irregular' => array( 'osztaly' => 'osztalyok', 'gyujto' => 'gyujtok', 'gyujto_osztaly' => 'gyujtok_osztalyok', 'gyujtoosztaly' => 'gyujtok_osztalyok' //ez itt a test suite miatt kell )));