Nel gioco che sto sviluppando, ho un "tabellone" ad esagoni. Mi sono inventato un sistema per cui utilizzo il piano cartesiano per spostarmi in una delle sei direzioni. Spostarsi diagonalmente fa si che in alcuni casi si debba incrementare il valore della x, in altri casi no. Prima ho disegnato su carta il piano cartesiano con le coordinate, poi ho scritto un test che mi controllasse la classe. Io SO cosa voglio, ma non so che codice devo scrivere. Con il test, ci ho messo pochi minuti a realizzare la classe Coordinata. Senza test, … mi sono imbattuto in diversi problemi che mi avevano tenuto "bloccato" diverse ore …
PS. Non sono un esperto di test, ma sono un amante dello stato d’animo che si raggiunge quando non ci si deve più preoccupare di come va il codice. Basta fare un click e tutti i test testeranno il codice. Credetemi. Avere la certezza MATEMATICA che il vostro codice FA ESATTAMENTE QUELLO CHE VOLETE senza se e senza ma.
Chi fa TDD scrive prima i test e poi il codice. Io scrivo i test solo in momenti particolari: quando sono stanco o quando non ho tempo per scrivere il codice effettivo.
<?php
require_once dirname ( __FILE__ ) . '/../../classes/Coordinata.php';
/**
* Test class for Coordinata.
* Generated by PHPUnit on 2011-05-31 at 23:29:23.
*/
class CoordinataTest extends PHPUnit_Framework_TestCase {
/**
* @var Coordinata
*/
protected $object;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*/
protected function setUp () {
$this->object = new Coordinata;
}
/**
* Tears down the fixture, for example, closes a network connection.
* This method is called after a test is executed.
*/
protected function tearDown () {
}
public static function provider () {
return array (
array ( 0, 0, array ( 'x' => 0, 'y' => 0 ) ),
array ( 1, 0, array ( 'x' => 1, 'y' => 0 ) ),
array ( 0, 1, array ( 'x' => 0, 'y' => 1 ) ),
array ( -1, 0, array ( 'x' => -1, 'y' => 0 ) )
);
}
/**
* @dataProvider provider
*/
public function testGetPosition ( $x, $y, $coordinata ) {
$obj = new Coordinata ( array ( 'x' => $x, 'y' => $y ) );
$this->assertEquals ( $obj->getPosition (), $coordinata );
}
public function testInitialPositionIsZeroZero () {
$obj = new Coordinata ( );
$this->assertEquals ( $obj->getPosition (), array ( 'x' => 0, 'y' => 0 ) );
}
public function testSetPosition ( ) {
// Remove the following lines when you implement this test.
$this->markTestIncomplete (
'This test has not been implemented yet.'
);
}
public static function providerMuoviASinistra () {
return array (
array ( 0, 0, array ( 'x' => -1, 'y' => 0 ) ),
array ( 1, 0, array ( 'x' =>0, 'y' => 0 ) ),
array ( 0, 1, array ( 'x' => -1, 'y' => 1 ) ),
array ( -1, 0, array ( 'x' => -2, 'y' => 0 ) )
);
}
/**
* @dataProvider providerMuoviASinistra
*/
public function testMuoviASinistra ($a, $b, $c) {
$obj = new Coordinata ( array (
'x' => $a,
'y' => $b,
) );
$obj->muoviASinistra();
$this->assertEquals ( $obj->getPosition (), $c );
}
public static function providerMuoviADestra () {
return array (
array ( 0, 0, array ( 'x' => 1, 'y' => 0 ) ),
array ( 1, 0, array ( 'x' => 2, 'y' => 0 ) ),
array ( 0, 1, array ( 'x' => 1, 'y' => 1 ) ),
array ( -1, 0, array ( 'x' => 0, 'y' => 0 ) )
);
}
/**
* @dataProvider providerMuoviADestra
*/
public function testMuoviADestra ($a, $b, $c) {
$obj = new Coordinata ( array (
'x' => $a,
'y' => $b,
) );
$obj->muoviADestra();
$this->assertEquals ( $obj->getPosition (), $c );
}
public static function providerInAltoASinistra () {
return array (
array ( 0, -1, array ( 'x' => -1, 'y' => 0 ) ),
array ( 1, -1, array ( 'x' => 0, 'y' => 0 ) ),
array ( 1, 0, array ( 'x' => 1, 'y' => 1 ) ),
array ( 0, 0, array ( 'x' => 0, 'y' => 1 ) )
);
}
/**
* @dataProvider providerInAltoASinistra
*/
public function testMuoviInAltoASinistra ( $a, $b, $c ) {
$obj = new Coordinata ( array (
'x' => $a,
'y' => $b,
) );
$obj->muoviInAltoASinistra ();
$this->assertEquals ( $obj->getPosition (), $c );
}
public static function providerInAltoADestra () {
return array (
array ( 0, 0, array ( 'x' => 1, 'y' => 1 ) ),
array ( 0, -1, array ( 'x' => 0, 'y' => 0 ) ),
array ( -1, 0, array ( 'x' => 0, 'y' => 1 ) ),
array ( 1, -1, array ( 'x' => 1, 'y' => 0 ) )
);
}
/**
* @dataProvider providerInAltoADestra
*/
public function testMuoviInAltoADestra ( $a, $b, $c ) {
$obj = new Coordinata ( array (
'x' => $a,
'y' => $b,
) );
$obj->muoviInAltoADestra ();
$this->assertEquals ( $obj->getPosition (), $c );
}
public static function providerInBassoASinistra () {
return array (
array ( 1, 1, array ( 'x' => 0, 'y' => 0 ) ),
array ( 0, 0, array ( 'x' => 0, 'y' => -1 ) ),
array ( 0, 1, array ( 'x' => -1, 'y' => 0 ) ),
array ( 1, 0, array ( 'x' => 1, 'y' => -1 ) )
);
}
/**
* @dataProvider providerInBassoASinistra
*/
public function testMuoviInBassoASinistra ( $a, $b, $c ) {
$obj = new Coordinata ( array (
'x' => $a,
'y' => $b,
) );
$obj->muoviInBassoASinistra ();
$this->assertEquals ( $obj->getPosition (), $c );
}
public static function providerInBassooADestra () {
return array (
array ( 0, 0, array ( 'x' => 1, 'y' => -1 ) ),
array ( 0, 1, array ( 'x' => 0, 'y' => 0 ) ),
array ( -1, 0, array ( 'x' => 0, 'y' => -1 ) ),
array ( 1, 1, array ( 'x' => 1, 'y' => 0 ) )
);
}
/**
* @dataProvider providerInBassooADestra
*/
public function testMuoviInBassoADestra ($a, $b, $c) {
$obj = new Coordinata ( array (
'x' => $a,
'y' => $b,
) );
$obj->muoviInBassoADestra ();
$this->assertEquals ( $obj->getPosition (), $c );
}
}
?>
Ecco un altro test che ho fatto per crearmi un mio piccolo Model:
Vi spiego lo scenario per farvi comprendere meglio la mia situazione. Sto sviluppando un browser game. Ho bisogno di una classe che gestisca tutto il Model. Quello che vorrei, è qualche cosa di simile:
In particolare vorrei che con del codice come questo
$utenti = new Utenti;
sia poi possibile fare una query in tutta la tabella
$utenti->findAll();
oppure solo alcuni campi
$utenti->findAll(array('nome','cognome'));
e magari in particolari condizioni
$utenti->findAll(array('nome','cognome'),array('id'=>33));
Come faccio a realizzare una cosa del genere? Boh! Creiamo il test. Il grosso del lavoro lo lascio a Netbeans. Ora vi mostro il test che ho scritto per testare $utenti->orderBy();
Io sto dicendo che voglio che $obj->findOrderBy(array(‘id’=>‘desc’)); mi restituisca una query in un modo particolare.
public function testOrderBy () {
$obj = new Model ( 'persone', true );
$this->assertEquals ( 'select * from persone order by id desc', $obj->findOrderBy ( array (
'id' => 'desc'
) ) );
$this->assertEquals ( 'select * from persone where pasta = "spaghetti" order by id desc', $obj->findOrderBy ( array (
'id' => 'desc'
), array (
'pasta' => 'spaghetti'
) ) );
}
Ho scritto il test, ma non ancora il codice di Model. Lanciando il test, questo mi dirà che ho cazzato. Vado a scrivere il codice e se ho fatto tutto bene il test diventerà verde. Io sarò una persona felice. =). Uso i test quando sono in difficoltà. Nel test mettiamo prima il valore che ci aspettiamo, e poi quello che ci ritorna il nostro codice. Il bello del test è che ti dice "occhio che non stai ottenendo il risultato che ti aspetti.
Ecco un altro test banale
public function testFind () {
$obj = new Model ( 'capelli', true );
$this->assertEquals ( 'select * from capelli', $obj->find () );
$obj = new Model ( 'users', true );
$this->assertEquals ( 'select * from users', $obj->find () );
}
Ed ora la parte più bella. Supponiamo che io abbia scritto questo test. Supponiamo che il mio codice faccia schifo, pur funzionando perfettamente. Io posso BUTTARE VIA il mio codice, poi riscriverlo usando i test. Credetemi: è un OTTIMO modo per migliorare il proprio modo di scrivere. Non solo. Potete "passare" un vostro test ad un collega, ed a voi non importa che codice scriverà: se il test passa voi avete la certezza assoluta che il codice del collega si comporta ESATTAMENTE COME VOLETE:
<?php
require_once dirname ( __FILE__ ) . '/../../classes/Model.php';
class ModelTest extends PHPUnit_Framework_TestCase {
protected $object;
protected function setUp () {
$this->object = new Model;
}
protected function tearDown () {
}
public function testCount () {
$obj = new Model ( 'capelli', true );
$this->assertEquals ( 'select count(*) num from capelli', $obj->count () );
}
public function testFind () {
$obj = new Model ( 'capelli', true );
$this->assertEquals ( 'select * from capelli', $obj->find () );
$obj = new Model ( 'users', true );
$this->assertEquals ( 'select * from users', $obj->find () );
}
public function testOrderBy () {
$obj = new Model ( 'persone', true );
$this->assertEquals ( 'select * from persone order by id desc', $obj->findOrderBy ( array (
'id' => 'desc'
) ) );
$this->assertEquals ( 'select * from persone where pasta = "spaghetti" order by id desc', $obj->findOrderBy ( array (
'id' => 'desc'
), array (
'pasta' => 'spaghetti'
) ) );
}
public function testCountwhere () {
$this->markTestIncomplete (
'This test has not been implemented yet.'
);
}
public function testFindAll () {
$this->markTestIncomplete (
'This test has not been implemented yet.'
);
}
public function testUpdate () {
$this->markTestIncomplete (
'This test has not been implemented yet.'
);
}
public function testCreate () {
$this->markTestIncomplete (
'This test has not been implemented yet.'
);
}
public function testDelete () {
$this->markTestIncomplete (
'This test has not been implemented yet.'
);
}
public function testTruncate () {
$this->markTestIncomplete (
'This test has not been implemented yet.'
);
}
public function testLastInsertId () {
$this->markTestIncomplete (
'This test has not been implemented yet.'
);
}
}