+ All Categories
Home > Documents > Il testing con Zend Frameworkstatic.zend.com/topics/Testing-ZF-ita.pdf · © All rights reserved....

Il testing con Zend Frameworkstatic.zend.com/topics/Testing-ZF-ita.pdf · © All rights reserved....

Date post: 24-Feb-2019
Category:
Upload: letuyen
View: 215 times
Download: 0 times
Share this document with a friend
51
© All rights reserved. Zend Technologies, Inc. Il testing con Zend Framework Enrico Zimuel Senior Consultant & Architect Zend Technologies
Transcript

© All rights reserved. Zend Technologies, Inc.

Il testing con Zend FrameworkEnrico ZimuelSenior Consultant & ArchitectZend Technologies

© 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

© All rights reserved. Zend Technologies, Inc.

Perchè testare il codice?

© 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

© 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

6 © All rights reserved. Zend Technologies, Inc.

Benefici psicologici per gli sviluppatori

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

7 © All rights reserved. Zend Technologies, Inc.

Testing non è … ricaricare una pagina

8 © All rights reserved. Zend Technologies, Inc.

Testing non è … var_dump()

9 © All rights reserved. Zend Technologies, Inc.

Testing è … riproducibile

10 © All rights reserved. Zend Technologies, Inc.

Testing è … automatizzabile

© 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

© 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

13 © All rights reserved. Zend Technologies, Inc.

Le basi del testing

© 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

© 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{}

© 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() { }}

© 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(); }}

© 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); }}

© 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

20 © All rights reserved. Zend Technologies, Inc.

Alcuni termini del testing

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

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

© 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

24 © All rights reserved. Zend Technologies, Inc.

Testing semi-funzionalein 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

© 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

© 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>

© 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_');

© 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{}

© 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(); }}

© 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'); // ... }}

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

© 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

© 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"

© 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"

© All rights reserved. Zend Technologies, Inc.

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

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

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

● ognuna ha una variante "Not"

© 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"

© 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"

© 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);}

© 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');}

41 © All rights reserved. Zend Technologies, Inc.

Alcuni casi avanzati di testing

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

© 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(); }

}

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

© 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()); }}

© 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'); }

© 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

© 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'); }

49 © All rights reserved. Zend Technologies, Inc.

Conclusioni

© 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à

© All rights reserved. Zend Technologies, Inc.

Grazie!

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


Recommended