il testing con zend framework

51
© All rights reserved. Zend Technologies, Inc. Il testing con Zend Framework Enrico Zimuel Senior Consultant & Architect Zend Technologies

Upload: zend-technologies

Post on 17-May-2015

546 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Il testing con Zend FrameworkEnrico ZimuelSenior Consultant & ArchitectZend Technologies

Page 2: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Sommario● Introduzione allo Unit Testing in PHP● Le funzionalità di base di test con ZF● Alcuni scenari avanzati di testing con ZF

Page 3: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Perchè testare il codice?

Page 4: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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

Page 5: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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

Page 6: Il testing con zend framework

6 © All rights reserved. Zend Technologies, Inc.

Benefici psicologici per gli sviluppatori

Quando il test è ok, gli sviluppatori sono piùconfidenti e motivati!

Page 7: Il testing con zend framework

7 © All rights reserved. Zend Technologies, Inc.

Testing non è … ricaricare una pagina

Page 8: Il testing con zend framework

8 © All rights reserved. Zend Technologies, Inc.

Testing non è … var_dump()

Page 9: Il testing con zend framework

9 © All rights reserved. Zend Technologies, Inc.

Testing è … riproducibile

Page 10: Il testing con zend framework

10 © All rights reserved. Zend Technologies, Inc.

Testing è … automatizzabile

Page 11: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

In un buon testing …● Si definiscono i comportamenti● Si forniscono esempi su scenari d'utilizzo● Si definiscono le aspettative

Page 12: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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

Page 13: Il testing con zend framework

13 © All rights reserved. Zend Technologies, Inc.

Le basi del testing

Page 14: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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

Page 15: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Creare una classe di test● Solitamente il nome termina per Test

class EntryTest extends PHPUnit_Framework_TestCase{}

class EntryTest extends PHPUnit_Framework_TestCase{}

Page 16: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Scrivere un metodo che definisce il comportamento

● prefisso “test”

class EntryTest extends PHPUnit_Framework_TestCase{ public function testMaySetTimestampWithString() { }}

class EntryTest extends PHPUnit_Framework_TestCase{ public function testMaySetTimestampWithString() { }}

Page 17: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Scrivere il codice per il comportamento

class EntryTest extends PHPUnit_Framework_TestCase{ public function testMaySetTimestampWithString() { $string = 'Fri, 7 May 2010 09:26:03 -0700'; $ts = strtotime($string); $this->entry->setTimestamp($string); $setValue = $this->entry->getTimestamp(); }}

class EntryTest extends PHPUnit_Framework_TestCase{ public function testMaySetTimestampWithString() { $string = 'Fri, 7 May 2010 09:26:03 -0700'; $ts = strtotime($string); $this->entry->setTimestamp($string); $setValue = $this->entry->getTimestamp(); }}

Page 18: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Scrivere asserzioni per un comportamento atteso

class EntryTest extends PHPUnit_Framework_TestCase{ public function testMaySetTimestampWithString() { $string = 'Fri, 7 May 2010 09:26:03 -0700'; $ts = strtotime($string); $this->entry->setTimestamp($string); $setValue = $this->entry->getTimestamp(); $this->assertSame($ts, $setValue); }}

class EntryTest extends PHPUnit_Framework_TestCase{ public function testMaySetTimestampWithString() { $string = 'Fri, 7 May 2010 09:26:03 -0700'; $ts = strtotime($string); $this->entry->setTimestamp($string); $setValue = $this->entry->getTimestamp(); $this->assertSame($ts, $setValue); }}

Page 19: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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

Page 20: Il testing con zend framework

20 © All rights reserved. Zend Technologies, Inc.

Alcuni termini del testing

Page 21: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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()

Page 22: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Test doubles● Stubs

Sostituire un oggetto con un altro per continuare il test

● Mock ObjectsSostituire un oggetto con un altro forzandone le aspettative (restituendo valori prestabiliti per i metodi)

Page 23: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Alcune tipologie di test● Testing condizionali

Testing solo al verificarsi di alcune condizioni d'ambiente

● Testing funzionali e d'integrazioneTesting del sistema per verificare i comportamenti attesi; testing delle unità e delle loro interazioni

Page 24: Il testing con zend framework

24 © All rights reserved. Zend Technologies, Inc.

Testing semi-funzionalein Zend Framework

Page 25: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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

Page 26: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

L'ambiente PHPUnit● Struttura delle directory

tests|-- application| `-- controllers|-- Bootstrap.php|-- library| `-- Custom`-- phpunit.xml

4 directories, 2 files

tests|-- application| `-- controllers|-- Bootstrap.php|-- library| `-- Custom`-- phpunit.xml

4 directories, 2 files

Page 27: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

L'ambiente PHPUnit (2)● phpunit.xml

<phpunit bootstrap="./Bootstrap.php"> <testsuite name="Test Suite"> <directory>./</directory> </testsuite> <filter> <whitelist> <directory suffix=".php">../library/</directory> <directory suffix=".php">../application/</directory> <exclude> <directory suffix=".phtml">../application/</directory> </exclude> </whitelist> </filter></phpunit>

<phpunit bootstrap="./Bootstrap.php"> <testsuite name="Test Suite"> <directory>./</directory> </testsuite> <filter> <whitelist> <directory suffix=".php">../library/</directory> <directory suffix=".php">../application/</directory> <exclude> <directory suffix=".phtml">../application/</directory> </exclude> </whitelist> </filter></phpunit>

Page 28: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

L'ambiente PHPUnit (3)● Bootstrap.php

$rootPath = realpath(dirname(__DIR__));if (!defined('APPLICATION_PATH')) { define('APPLICATION_PATH', $rootPath . '/application');}if (!defined('APPLICATION_ENV')) { define('APPLICATION_ENV', 'testing');}set_include_path(implode(PATH_SEPARATOR, array( '.', $rootPath . '/library', get_include_path(),)));require_once 'Zend/Loader/Autoloader.php';$loader = Zend_Loader_Autoloader::getInstance();$loader->registerNamespace('Custom_');

$rootPath = realpath(dirname(__DIR__));if (!defined('APPLICATION_PATH')) { define('APPLICATION_PATH', $rootPath . '/application');}if (!defined('APPLICATION_ENV')) { define('APPLICATION_ENV', 'testing');}set_include_path(implode(PATH_SEPARATOR, array( '.', $rootPath . '/library', get_include_path(),)));require_once 'Zend/Loader/Autoloader.php';$loader = Zend_Loader_Autoloader::getInstance();$loader->registerNamespace('Custom_');

Page 29: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Creare una classe di test● Estendere la Zend_Test_PHPUnit_ControllerTestCase

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{}

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{}

Page 30: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Bootstrap dell'applicazione● Creare un'istanza di Zend_Application e

referenziarla nel setUp()

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ public function setUp() { $this->bootstrap = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini' ); parent::setUp(); }}

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ public function setUp() { $this->bootstrap = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini' ); parent::setUp(); }}

Page 31: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Creazione e dispatch di una richiesta

● Metodo semplice: dispatch di una “url”

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function testStaticPageHasGoodStructure() { $this->dispatch('/example/page'); // ... }}

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function testStaticPageHasGoodStructure() { $this->dispatch('/example/page'); // ... }}

Page 32: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

● Avanzato: personalizzare l'oggetto della richiesta prima di eseguire il dispatchclass ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function testXhrRequestReturnsJson() { $this->getRequest() ->setHeader('X-Requested-With', 'XMLHttpRequest') ->setQuery('format', 'json'); $this->dispatch('/example/xhr-endpoint'); // ... }}

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function testXhrRequestReturnsJson() { $this->getRequest() ->setHeader('X-Requested-With', 'XMLHttpRequest') ->setQuery('format', 'json'); $this->dispatch('/example/xhr-endpoint'); // ... }}

Creazione e dispatch di una richiesta (2)

Page 33: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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

Page 34: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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"

Page 35: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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"

Page 36: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Asserzioni su Redirect● assertRedirect($message = '')

● assertRedirectTo($url, $message = '')

● assertRedirectRegex($pattern, $message = '')

● ognuna ha una variante "Not"

Page 37: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Asserzioni sulle risposte● assertResponseCode($code, $message = '')

● assertHeader($header, $message = '')

● assertHeaderContains($header, $match, $message = '')

● assertHeaderRegex($header, $pattern, $message = '')

● ognuna ha una variante "Not"

Page 38: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Asserzioni sulle richieste● assertModule($module, $message = '')

● assertController($controller, $message = '')

● assertAction($action, $message = '')

● assertRoute($route, $message = '')

● ognuna ha una variante "Not"

Page 39: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Esempi di asserzioni

public function testSomeStaticPageHasGoodStructure(){ $this->dispatch('/example/page'); $this->assertResponseCode(200); $this->assertQuery('div#content p'); $this->assertQueryCount('div#sidebar ul li', 3);}

public function testSomeStaticPageHasGoodStructure(){ $this->dispatch('/example/page'); $this->assertResponseCode(200); $this->assertQuery('div#content p'); $this->assertQueryCount('div#sidebar ul li', 3);}

Page 40: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Esempi di asserzioni (2)

public function testXhrRequestReturnsJson(){ // ... $this->assertNotRedirect(); $this->assertHeaderContains( 'Content-Type', 'application/json');}

public function testXhrRequestReturnsJson(){ // ... $this->assertNotRedirect(); $this->assertHeaderContains( 'Content-Type', 'application/json');}

Page 41: Il testing con zend framework

41 © All rights reserved. Zend Technologies, Inc.

Alcuni casi avanzati di testing

Page 42: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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()

Page 43: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Esempio

class Blog_Model_EntryTest extends PHPUnit_Framework_TestCase{ public function setUp() { $this->bootstrap = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini' ); $this->bootstrap->bootstrap('modules');

$this->model = new Blog_Model_Entry(); }

}

class Blog_Model_EntryTest extends PHPUnit_Framework_TestCase{ public function setUp() { $this->bootstrap = new Zend_Application( APPLICATION_ENV, APPLICATION_PATH . '/configs/application.ini' ); $this->bootstrap->bootstrap('modules');

$this->model = new Blog_Model_Entry(); }

}

Page 44: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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()

Page 45: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Esempio

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function loginUser($user) { $params = array('user' => $user); $adapter = new Custom_Auth_TestAdapter( $params); $auth = Zend_Auth::getInstance(); $auth->authenticate($adapter); $this->assertTrue($auth->hasIdentity()); }}

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function loginUser($user) { $params = array('user' => $user); $adapter = new Custom_Auth_TestAdapter( $params); $auth = Zend_Auth::getInstance(); $auth->authenticate($adapter); $this->assertTrue($auth->hasIdentity()); }}

Page 46: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Esempio (2)

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function testAdminUserCanAccessAdmin() { $this->loginUser('admin'); $this->dispatch('/example/admin'); $this->assertQuery('div#content.admin'); }

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function testAdminUserCanAccessAdmin() { $this->loginUser('admin'); $this->dispatch('/example/admin'); $this->assertQuery('div#content.admin'); }

Page 47: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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

Page 48: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Esempio

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function testHighlightedTextAfterSearch() { $this->getRequest()->setQuery( 'search', 'foobar'); $this->dispatch('/search');

$this->resetRequest(); $this->resetResponse();

$this->dispatch('/example/page'); $this->assertQueryContains( 'span.highlight', 'foobar'); }

class ExampleControllerTest extends Zend_Test_PHPUnit_ControllerTestCase{ // ... public function testHighlightedTextAfterSearch() { $this->getRequest()->setQuery( 'search', 'foobar'); $this->dispatch('/search');

$this->resetRequest(); $this->resetResponse();

$this->dispatch('/example/page'); $this->assertQueryContains( 'span.highlight', 'foobar'); }

Page 49: Il testing con zend framework

49 © All rights reserved. Zend Technologies, Inc.

Conclusioni

Page 50: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

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à

Page 51: Il testing con zend framework

© All rights reserved. Zend Technologies, Inc.

Grazie!

Per maggiori informazioni:http://www.zend.comhttp://framework.zend.com