More Related Content
Similar to Il testing con zend framework (20)
More from Zend by Rogue Wave Software (20)
Il testing con zend framework
- 1. Il testing con Zend
Framework
Enrico Zimuel
Senior Consultant & Architect
Zend Technologies
© All rights reserved. Zend Technologies, Inc.
- 2. Sommario
● Introduzione allo Unit Testing in PHP
● Le funzionalità di base di test con ZF
● Alcuni scenari avanzati di testing con ZF
© All rights reserved. Zend Technologies, Inc.
- 4. Semplificare la manutenzione
● Il testing definisce le aspettative
● Il testing descrive i comportamenti
dell'applicazione
● Il testing identifica i cambiamenti nel
codice sorgente che violano
(“rompono”) i comportamenti attesi del
software
© All rights reserved. Zend Technologies, Inc.
- 5. Quantificare la qualità del codice
● Copertura del codice (code coverage)
effettuata dagli strumenti di testing
● I metodi di test documentano i
comportamenti attesi del software
© All rights reserved. Zend Technologies, Inc.
- 6. Benefici psicologici per gli sviluppatori
Quando il test è ok, gli sviluppatori sono più
confidenti e motivati!
6 © All rights reserved. Zend Technologies, Inc.
- 7. Testing non è … ricaricare una pagina
7 © All rights reserved. Zend Technologies, Inc.
- 8. Testing non è … var_dump()
8 © All rights reserved. Zend Technologies, Inc.
- 9. Testing è … riproducibile
9 © All rights reserved. Zend Technologies, Inc.
- 10. Testing è … automatizzabile
10 © All rights reserved. Zend Technologies, Inc.
- 11. In un buon testing …
● Si definiscono i comportamenti
● Si forniscono esempi su scenari d'utilizzo
● Si definiscono le aspettative
© All rights reserved. Zend Technologies, Inc.
- 12. PHP testing frameworks
● PHPT
▶ Utilizzato da PHP, da PEAR e da alcune
librerie indipendenti
● SimpleTest
▶ Un framework di testing in stile JUnit
● PHPUnit
▶ Un framework di testing in stile JUnit
▶ De facto lo standard di testing in PHP
© All rights reserved. Zend Technologies, Inc.
- 13. Le basi del testing
13 © All rights reserved. Zend Technologies, Inc.
- 14. Scrivere unit test
● Creare una classe di test
● Creare uno o più metodi che definiscono dei
comportamenti
▶ Descrivere il comportamento in un
linguaggio naturale
● Scrivere codice che definisce il comportamento
▶ Scrivere codice utilizzando l'API
● Scrivere le asserzioni per definire il
comportamento atteso
© All rights reserved. Zend Technologies, Inc.
- 15. Creare una classe di test
● Solitamente il nome termina per Test
class EntryTest
class EntryTest
extends PHPUnit_Framework_TestCase
extends PHPUnit_Framework_TestCase
{{
}}
© All rights reserved. Zend Technologies, Inc.
- 16. Scrivere un metodo che definisce il
comportamento
● prefisso “test”
class EntryTest
class EntryTest
extends PHPUnit_Framework_TestCase
extends PHPUnit_Framework_TestCase
{{
public function testMaySetTimestampWithString()
public function testMaySetTimestampWithString()
{{
}}
}}
© All rights reserved. Zend Technologies, Inc.
- 17. Scrivere il codice per il comportamento
class EntryTest
class EntryTest
extends PHPUnit_Framework_TestCase
extends PHPUnit_Framework_TestCase
{{
public function testMaySetTimestampWithString()
public function testMaySetTimestampWithString()
{{
$string = 'Fri, 7 May 2010 09:26:03 -0700';
$string = 'Fri, 7 May 2010 09:26:03 -0700';
$ts
$ts = strtotime($string);
= strtotime($string);
$this->entry->setTimestamp($string);
$this->entry->setTimestamp($string);
$setValue = $this->entry->getTimestamp();
$setValue = $this->entry->getTimestamp();
}}
}}
© All rights reserved. Zend Technologies, Inc.
- 18. Scrivere asserzioni per un
comportamento atteso
class EntryTest
class EntryTest
extends PHPUnit_Framework_TestCase
extends PHPUnit_Framework_TestCase
{{
public function testMaySetTimestampWithString()
public function testMaySetTimestampWithString()
{{
$string = 'Fri, 7 May 2010 09:26:03 -0700';
$string = 'Fri, 7 May 2010 09:26:03 -0700';
$ts
$ts = strtotime($string);
= strtotime($string);
$this->entry->setTimestamp($string);
$this->entry->setTimestamp($string);
$setValue = $this->entry->getTimestamp();
$setValue = $this->entry->getTimestamp();
$this->assertSame($ts, $setValue);
$this->assertSame($ts, $setValue);
}}
}}
© All rights reserved. Zend Technologies, Inc.
- 19. Eseguire il test
● Fallimento?
▶ Verifica il test e le asserzioni per eventuali
errori di battitura o casi d'uso
▶ Verifica la classe che si stà testando
▶ Eseguire le correzioni e rilanciare il test
● Successo?
▶ Creare il prossimo test di comportamento
o continuare con le modifiche sul codice
del software
© All rights reserved. Zend Technologies, Inc.
- 21. Test scaffolding
● Essere sicuri che l'ambiente di testing sia
libero da pre-requisiti
● Inizializzare le dipendenze necessarie per
eseguire il test
● Di solito l'inizializzazione dell'ambiente di
test avviene nel metodo setUp()
© All rights reserved. Zend Technologies, Inc.
- 22. Test doubles
● Stubs
Sostituire un oggetto con un altro per
continuare il test
● Mock Objects
Sostituire un oggetto con un altro
forzandone le aspettative (restituendo
valori prestabiliti per i metodi)
© All rights reserved. Zend Technologies, Inc.
- 23. Alcune tipologie di test
● Testing condizionali
Testing solo al verificarsi di alcune
condizioni d'ambiente
● Testing funzionali e d'integrazione
Testing del sistema per verificare i
comportamenti attesi; testing delle unità
e delle loro interazioni
© All rights reserved. Zend Technologies, Inc.
- 25. Fasi principali
● Setup dell'ambiente phpUnit
● Creare uno scenario di test (TestCase)
basato su un Controller
(ControllerTestCase)
● Bootstrap dell'applicazione
● Creazione di una richiesta e dispatch
● Eseguire asserzioni sulle risposte
© All rights reserved. Zend Technologies, Inc.
- 26. L'ambiente PHPUnit
● Struttura delle directory
tests
tests
|-- application
|-- application
|| `-- controllers
`-- controllers
|-- Bootstrap.php
|-- Bootstrap.php
|-- library
|-- library
|| `-- Custom
`-- Custom
`-- phpunit.xml
`-- phpunit.xml
4 directories, 2 files
4 directories, 2 files
© All rights reserved. Zend Technologies, Inc.
- 27. L'ambiente PHPUnit (2)
● phpunit.xml
<phpunit bootstrap="./Bootstrap.php">
<phpunit bootstrap="./Bootstrap.php">
<testsuite name="Test Suite">
<testsuite name="Test Suite">
<directory>./</directory>
<directory>./</directory>
</testsuite>
</testsuite>
<filter>
<filter>
<whitelist>
<whitelist>
<directory
<directory
suffix=".php">../library/</directory>
suffix=".php">../library/</directory>
<directory
<directory
suffix=".php">../application/</directory>
suffix=".php">../application/</directory>
<exclude>
<exclude>
<directory
<directory
suffix=".phtml">../application/</directory>
suffix=".phtml">../application/</directory>
</exclude>
</exclude>
</whitelist>
</whitelist>
</filter>
</filter>
</phpunit>
</phpunit>
© All rights reserved. Zend Technologies, Inc.
- 28. L'ambiente PHPUnit (3)
● Bootstrap.php
$rootPath == realpath(dirname(__DIR__));
$rootPath realpath(dirname(__DIR__));
if (!defined('APPLICATION_PATH')) {{
if (!defined('APPLICATION_PATH'))
define('APPLICATION_PATH',
define('APPLICATION_PATH',
$rootPath .. '/application');
$rootPath '/application');
}}
if (!defined('APPLICATION_ENV')) {{
if (!defined('APPLICATION_ENV'))
define('APPLICATION_ENV', 'testing');
define('APPLICATION_ENV', 'testing');
}}
set_include_path(implode(PATH_SEPARATOR, array(
set_include_path(implode(PATH_SEPARATOR, array(
'.',
'.',
$rootPath .. '/library',
$rootPath '/library',
get_include_path(),
get_include_path(),
)));
)));
require_once 'Zend/Loader/Autoloader.php';
require_once 'Zend/Loader/Autoloader.php';
$loader == Zend_Loader_Autoloader::getInstance();
$loader Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace('Custom_');
$loader->registerNamespace('Custom_');
© All rights reserved. Zend Technologies, Inc.
- 29. Creare una classe di test
● Estendere la Zend_Test_PHPUnit_ControllerTestCase
class ExampleControllerTest
class ExampleControllerTest
extends Zend_Test_PHPUnit_ControllerTestCase
extends Zend_Test_PHPUnit_ControllerTestCase
{{
}}
© All rights reserved. Zend Technologies, Inc.
- 30. Bootstrap dell'applicazione
● Creare un'istanza di Zend_Application e
referenziarla nel setUp()
class ExampleControllerTest
class ExampleControllerTest
extends Zend_Test_PHPUnit_ControllerTestCase
extends Zend_Test_PHPUnit_ControllerTestCase
{{
public function setUp()
public function setUp()
{{
$this->bootstrap = new Zend_Application(
$this->bootstrap = new Zend_Application(
APPLICATION_ENV,
APPLICATION_ENV,
APPLICATION_PATH
APPLICATION_PATH
. '/configs/application.ini'
. '/configs/application.ini'
);
);
parent::setUp();
parent::setUp();
}}
}}
© All rights reserved. Zend Technologies, Inc.
- 31. Creazione e dispatch di una richiesta
● Metodo semplice: dispatch di una “url”
class ExampleControllerTest
class ExampleControllerTest
extends Zend_Test_PHPUnit_ControllerTestCase
extends Zend_Test_PHPUnit_ControllerTestCase
{{
// ...
// ...
public function testStaticPageHasGoodStructure()
public function testStaticPageHasGoodStructure()
{{
$this->dispatch('/example/page');
$this->dispatch('/example/page');
// ...
// ...
}}
}}
© All rights reserved. Zend Technologies, Inc.
- 32. Creazione e dispatch di una richiesta (2)
● Avanzato: personalizzare l'oggetto della
richiesta prima di eseguire il dispatch
class ExampleControllerTest
class ExampleControllerTest
extends Zend_Test_PHPUnit_ControllerTestCase
extends Zend_Test_PHPUnit_ControllerTestCase
{{
// ...
// ...
public function testXhrRequestReturnsJson()
public function testXhrRequestReturnsJson()
{{
$this->getRequest()
$this->getRequest()
->setHeader('X-Requested-With',
->setHeader('X-Requested-With',
'XMLHttpRequest')
'XMLHttpRequest')
->setQuery('format', 'json');
->setQuery('format', 'json');
$this->dispatch('/example/xhr-endpoint');
$this->dispatch('/example/xhr-endpoint');
// ...
// ...
}}
}}
© All rights reserved. Zend Technologies, Inc.
- 33. Creare asserzioni
● Tipiche asserzioni:
▶ Verifica della struttura della risposta e dei
markup
Utilizzando selettori CSS o query XPath
▶ Verificare il codice della risposta HTTP o
l'header di pagina
▶ Verificare artefatti sulla richiesta e sulla
risposta
© All rights reserved. Zend Technologies, Inc.
- 34. Asserzioni con selettori CSS
● assertQuery($path, $message = '')
● assertQueryContentContains(
$path, $match, $message = '')
● assertQueryContentRegex(
$path, $pattern, $message = '')
● assertQueryCount($path, $count, $message = '')
● assertQueryCountMin($path, $count, $message = '')
● assertQueryCountMax($path, $count, $message = '')
● ognuna ha una variante "Not"
© All rights reserved. Zend Technologies, Inc.
- 35. Asserzioni con selettori XPath
● assertXpath($path, $message = '')
● assertXpathContentContains(
$path, $match, $message = '')
● assertXpathContentRegex(
$path, $pattern, $message = '')
● assertXpathCount($path, $count, $message = '')
● assertXpathCountMin($path, $count, $message = '')
● assertXpathCountMax($path, $count, $message = '')
● ognuna ha una variante "Not"
© All rights reserved. Zend Technologies, Inc.
- 36. Asserzioni su Redirect
● assertRedirect($message = '')
● assertRedirectTo($url, $message = '')
● assertRedirectRegex($pattern, $message = '')
● ognuna ha una variante "Not"
© All rights reserved. Zend Technologies, Inc.
- 37. Asserzioni sulle risposte
● assertResponseCode($code, $message = '')
● assertHeader($header, $message = '')
● assertHeaderContains($header, $match,
$message = '')
● assertHeaderRegex($header, $pattern,
$message = '')
● ognuna ha una variante "Not"
© All rights reserved. Zend Technologies, Inc.
- 38. Asserzioni sulle richieste
● assertModule($module, $message = '')
● assertController($controller, $message = '')
● assertAction($action, $message = '')
● assertRoute($route, $message = '')
● ognuna ha una variante "Not"
© All rights reserved. Zend Technologies, Inc.
- 39. Esempi di asserzioni
public function testSomeStaticPageHasGoodStructure()
public function testSomeStaticPageHasGoodStructure()
{{
$this->dispatch('/example/page');
$this->dispatch('/example/page');
$this->assertResponseCode(200);
$this->assertResponseCode(200);
$this->assertQuery('div#content p');
$this->assertQuery('div#content p');
$this->assertQueryCount('div#sidebar ul li', 3);
$this->assertQueryCount('div#sidebar ul li', 3);
}}
© All rights reserved. Zend Technologies, Inc.
- 40. Esempi di asserzioni (2)
public function testXhrRequestReturnsJson()
public function testXhrRequestReturnsJson()
{{
// ...
// ...
$this->assertNotRedirect();
$this->assertNotRedirect();
$this->assertHeaderContains(
$this->assertHeaderContains(
'Content-Type', 'application/json');
'Content-Type', 'application/json');
}}
© All rights reserved. Zend Technologies, Inc.
- 42. Testing di modelli e risorse
● Problema:
Queste classi non vengono caricate con il
sistema di autoloading
● Soluzione:
Utilizzare il bootstrap di Zend_Application
per caricare manualmente le risorse
durante il setUp()
© All rights reserved. Zend Technologies, Inc.
- 43. Esempio
class Blog_Model_EntryTest
class Blog_Model_EntryTest
extends PHPUnit_Framework_TestCase
extends PHPUnit_Framework_TestCase
{{
public function setUp()
public function setUp()
{{
$this->bootstrap = new Zend_Application(
$this->bootstrap = new Zend_Application(
APPLICATION_ENV,
APPLICATION_ENV,
APPLICATION_PATH
APPLICATION_PATH
. '/configs/application.ini'
. '/configs/application.ini'
);
);
$this->bootstrap->bootstrap('modules');
$this->bootstrap->bootstrap('modules');
$this->model = new Blog_Model_Entry();
$this->model = new Blog_Model_Entry();
}}
}}
© All rights reserved. Zend Technologies, Inc.
- 44. Testing con autenticazione
● Problema:
Alcune azioni possono richiedere
un'autenticazione utente, come emularla
in fase di testing?
● Soluzione:
Eseguire un'autenticazione manuale
utilizzando Zend_Auth prima di eseguire il
dispatch()
© All rights reserved. Zend Technologies, Inc.
- 45. Esempio
class ExampleControllerTest
class ExampleControllerTest
extends Zend_Test_PHPUnit_ControllerTestCase
extends Zend_Test_PHPUnit_ControllerTestCase
{{
// ...
// ...
public function loginUser($user)
public function loginUser($user)
{{
$params = array('user' => $user);
$params = array('user' => $user);
$adapter = new Custom_Auth_TestAdapter(
$adapter = new Custom_Auth_TestAdapter(
$params);
$params);
$auth
$auth = Zend_Auth::getInstance();
= Zend_Auth::getInstance();
$auth->authenticate($adapter);
$auth->authenticate($adapter);
$this->assertTrue($auth->hasIdentity());
$this->assertTrue($auth->hasIdentity());
}}
}}
© All rights reserved. Zend Technologies, Inc.
- 46. Esempio (2)
class ExampleControllerTest
class ExampleControllerTest
extends Zend_Test_PHPUnit_ControllerTestCase
extends Zend_Test_PHPUnit_ControllerTestCase
{{
// ...
// ...
public function testAdminUserCanAccessAdmin()
public function testAdminUserCanAccessAdmin()
{{
$this->loginUser('admin');
$this->loginUser('admin');
$this->dispatch('/example/admin');
$this->dispatch('/example/admin');
$this->assertQuery('div#content.admin');
$this->assertQuery('div#content.admin');
}}
© All rights reserved. Zend Technologies, Inc.
- 47. Testing di pagine che dipendono da
altre azioni
● Problema:
Alcune azioni possono dipendere
dall'esito di altre, ad esempio una pagina
che evidenzia I risultati di un'operazione
di ricerca
● Soluzione:
Eseguire un doppio dispatch, resettando
la richiesta tra una chiamata e l'altra
© All rights reserved. Zend Technologies, Inc.
- 48. Esempio
class ExampleControllerTest
class ExampleControllerTest
extends Zend_Test_PHPUnit_ControllerTestCase
extends Zend_Test_PHPUnit_ControllerTestCase
{{
// ...
// ...
public function testHighlightedTextAfterSearch()
public function testHighlightedTextAfterSearch()
{{
$this->getRequest()->setQuery(
$this->getRequest()->setQuery(
'search', 'foobar');
'search', 'foobar');
$this->dispatch('/search');
$this->dispatch('/search');
$this->resetRequest();
$this->resetRequest();
$this->resetResponse();
$this->resetResponse();
$this->dispatch('/example/page');
$this->dispatch('/example/page');
$this->assertQueryContains(
$this->assertQueryContains(
'span.highlight', 'foobar');
'span.highlight', 'foobar');
}}
© All rights reserved. Zend Technologies, Inc.
- 50. Eseguire sempre il test!
● Test dei modelli, dei livelli di servizio, etc
● Eseguire test funzionali e di accettazione
per il workflow dell'applicazione, per la
struttura delle pagine, etc
● Testing = Scrivere codice migliore, più
affidabile e di qualità
© All rights reserved. Zend Technologies, Inc.