More Related Content
Similar to Il testing con zend framework
Similar to Il testing con zend framework (20)
More from Zend by Rogue Wave Software
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.