<?xml version="1.0"?>
<!-- $Id: mock_objects_documentation.xml 1890 2009-07-26 12:09:04Z lastcraft $ -->
<page title="Gli oggetti mock" here="Gli oggetti mock">
    <long_title>SimpleTest for PHP mock objects documentation</long_title>
    <content>
        <section name="what" title="Cosa sono gli oggetti mock?">
            <p>
				Gli oggetti mock svolgono due ruoli durante un test case: il ruolo di "attori"
				ed il ruolo di "critici"
            </p>
            <p>
                Nel ruolo di attore il mock ha la funzione di simulare il
				comportamento di un altro oggetto che durante il test sarebbe
				difficile o oneroso da instanziare.
				L'esempio classico è quello di una connessione ad un database.
				Allestire un database di collaudo all'inizio di ogni singolo testo
				rallenterebbe il collaudo a livelli inaccettabile e richiederebbe
				l'istallazione di un apposito motore di database e di dati di test sul
				server di test.
                Se ci fosse la possibilità di similare la connessione e restituire
				i dati selezionati per il collaudo non solo si otterrebbero dei
				test più pragmatici ma ci si potrebbe permettere di alimentare il
				codice con dati spuri per vederne la reazione.
				Avremmo la possibilità di simulare il caso di un database fuori linea o
				altre condizioni estreme di questo tipo, senza la necessità di generare
				i malfunzionamenti nella realtà.
				In altre parole, i mock possono fornire un grande controllo dell'ambiente
				di test.
            </p>
            <p>
				Se gli oggetti mock si comportassero solo come attori sarebbero
				semplicemente conosciuto come &quot;server stubs&quot;.
                Questi sono stati introdotti come pattern di sviluppo da  
				Robert Binder in (<a href="">Testing object-oriented systems</a> models, patterns, and tools,
                Addison-Wesley) nel 1999.
            </p>
            <p>
				Un server stub è la simulazione di un oggetto o di un componente.
				Dovrebbe rimpiazzare esplicitamente un componente con lo scopo di
				permettere il test o la prototipazione ma, fondamentalmente, resta un
				componente leggero.
				In questo modo permette ai test di eseguirsi con rapidità; nel caso
				la classe simulata ancora non esista affatto, permettono di eseguire
				comunque il codice.
            </p>
            <p>
				Tuttavia, gli oggetti mock non solo svolgono questo ruolo
				(restituiendo valori di ritorno alla loro interrogazione) ma
				sono anche sensibili ai messaggi che vengono loro inviati
				(tramite le expectation).
				Impostando i parametri attesi dalla invocazione di un metodo
				i mock si comportano da garanti della correttezza nelle chiamate
				ai metodi.
				Se le expectation non sono rispettare, i mock ci risparmiano la
				fatica di scrivere le assert fanno il lavoro sporco a posto nostro.
            </p>
            <p>
                Nel caso della connessione ad un database immaginrio sono
				in grado di verificare l'oggetto chiamante stia usando una query, supponiamo
				SQL, formalmente corretta.
				Una volta preparai con expectation sufficientemente rigorose
				non si avrà più bisogno di eseguire manualmente gli assert.
            </p>
        </section>
        <section name="creation" title="Creare oggetti mock">
            <p>
				Tutto quello di cui abbiamo bisogno è una classe esistente,
				supponiamo per la connessione al database, che abbia
				questo aspetto:
<php><![CDATA[
<strong>class DatabaseConnection {
    function DatabaseConnection() { }
    function query($sql) { }
    function selectQuery($sql) { }
}</strong>
]]></php>
				Non c'è bisogno che la classe sia stata implementata.
				Può bastare la sua interfaccia:
<php><![CDATA[
<strong>interface DatabaseConnection {
    function DatabaseConnection();
    function query($sql);
    function selectQuery($sql);
}</strong>
]]></php>
				Per generare una versione mock della classe si
				deve invocare il code generator:
<php><![CDATA[
require_once('simpletest/autorun.php');
require_once('database_connection.php');

<strong>Mock::generate('DatabaseConnection');</strong>
]]></php>
				Questo genera una classe clone
				chiamata <code>MockDatabaseConnection</code>.
				Adesso è possibile istanziare la nuova classe
				all'interno del test case:
<php><![CDATA[
require_once('simpletest/autorun.php');
require_once('database_connection.php');

Mock::generate('DatabaseConnection');

class MyTestCase extends UnitTestCase {

    function testSomething() {
        <strong>$connection = new MockDatabaseConnection();</strong>
    }
}
]]></php>
				La versione mock possiede tutti i metodi della classe originale.
                Anche i tipi degli argomenti vengono fedelmente preservati.
                Supponiamo che il metodo query si aspetti un oggetto <code>Query</code>:
<php><![CDATA[
<strong>class DatabaseConnection {
    function DatabaseConnection() { }
    function query(Query $query) { }
    function selectQuery(Query $query) { }
}</strong>
]]></php>
				Nel caso si invochi il metodo con un oggetto di tipo sbagliato o,
				peggio, con un non-object...
<php><![CDATA[
class MyTestCase extends UnitTestCase {

    function testSomething() {
        $connection = new MockDatabaseConnection();
        $connection->query('insert into accounts () values ()');
    }
}
]]></php>
                ...il codice lancerebbe un'eccezione di violazione di tipo
				esattamente come farebbe la classe originale.
            </p>
            <p>
				Anche se la versione mock possiede tutti i metodi della classe originale,
				questi restituiscono sfortunatamente <code>null</code>.
				Dal momenti che i metodi restituiscono sistematicamente <code>null</code>
				non risultano molto utili
				ed abbiamo bisogno di un modo per impostarle per
				avere un comportamento diverso:
            </p>
            <p>
                <a class="target" name="stub"><h2>Mocks as actors</h2></a>
            </p>
            <p>
                Modificare il valore di ritorno di un metodo da <code>null</code>
				a qualcos'altro è abbastanza semplice:
<php><![CDATA[
<strong>$connection->returns('query', 37)</strong>
]]></php>
                Adesso, ogni invocazione di
                <code><![CDATA[$connection->query()]]></code> restituisce 37.
                38 non ha niente di speciale: il valore di ritorno può
				essere arbitrariamente complesso.
            </p>
            <p>
				I parametri, in questo caso, sono irrilevanti e 
				una volta che si sia impostato il mock con questo
				sistema si otterrà sempre il medesimo valore qualsiasi essi siano
                Questa potrebbe apparire una replica poco convincente di una
				connessione al database, ma per un metodo di test di
				una mezza dozzina di righe, solitamente, è tutto quello
				di cui si può aver bisogno.
            </p>
            <p>
				Tuttavia, le cose non sono sempre così semplici.
				Uno dei problemi comuni si propone con le iterazioni, nelle quali
				il ritorno sistematico del solito valore può causare cicli
				infiniti dentro l'oggetto da collaudare.
				Per questo c'è bisogno di poter impostare sequenze di valori.
				Supponiamo di avere una semplice iterazione come questa:
<php><![CDATA[
class Iterator {
    function Iterator() { }
    function next() { }
}
]]></php>
				Stiamo parlando dell'iterazione più semplice che possa capitare.
				Se si assume che questa iterazione restituisca del testo
				fino a quando raggiunge la fine e che da quel momento
				debba restituire false, si potrebbe simularla così:
<php><![CDATA[
Mock::generate('Iterator');

class IteratorTest extends UnitTestCase() {

    function testASequence() {<strong>
        $iterator = new MockIterator();
        $iterator->returns('next', false);
        $iterator->returnsAt(0, 'next', 'First string');
        $iterator->returnsAt(1, 'next', 'Second string');</strong>
        ...
    }
}
]]></php>
				Quando <code>next()</code> di <code>MockIterator</code> viene invocata
				restituirà &quot;First string&quot; la prima volta e &quot;Second string&quot; la
				seconda mentre false tutte le altre volte.
				I valori di ritorno delle sequenze hanno precedenza sul valori
				di ritorno costante.
				Se può essere utile, si può pensare al valore di ritorno costante
				come il valore di ritorno di default.
            </p>
            <p>
				Un'altra situazione delicata è il caso di un'operazione 
                <code>get()</code> overloaded.
				Ad esempio è quando un'informazione conservata con una coppia nome/valore.
				Supponiamo di avere una classe di configurazione come questa:
<php><![CDATA[
class Configuration {
    function Configuration() { ... }
    function get($key) { ... }
}
]]></php>
				Questo è la tipica situazione in cui un oggetto mock risulta
				utile, dal momento che la configurazione varietà da macchina
				a macchina e perfino da test a test.
				Tuttavia, il problema è che i dati vengono recuperati mediante
				la chiamata al metodo <code>get()</code> e che, contemporaneamente,
				si desiderano valori differenti in corrispondenza di chiavi differenti.
				Fortunatamente, i mock dispongono di un sistema di filtraggio:
<php><![CDATA[
<strong>$config = &new MockConfiguration();
$config->returns('get', 'primary', array('db_host'));
$config->returns('get', 'admin', array('db_user'));
$config->returns('get', 'secret', array('db_password'));</strong>
]]></php>
				Il parametro aggiunto è l'elenco degli argomenti con
				i quali provare a fare un match.
				In questo caso, ad esempio, si sta provando il match con il solo
				argomento a disposizione il quale viene usato come look up key.
				Adesso, quando il metodo <code>get()</code> dell'oggetto mock
				viene invocato, come in...
<php><![CDATA[
$config->get('db_user')
]]></php>
                ...restituirà &quot;admin&quot;.
				Il risultato è stato ricavato tentando il match degli argomenti
				richiesti con ognuno dei valori dell'elenco, fino a che un match
				completo viene individuato.
            </p>
            <p>
				E' anche possibile impostare un argomento di default:
<php><![CDATA[<strong>
$config->returns('get', false, array('*'));</strong>
]]></php>
				Questo non è equivalente ad impostare il valore di
				ritorno che si deve avere in assenza di argomenti, come accade con:
<php><![CDATA[<strong>
$config->returns('get', false);</strong>
]]></php>
				Nel primo caso, viene accettato qualsiasi singolo argomento ma
				un argomento è comunque richiesto.
                Il secondo caso accetta un qualsiasi numero di argomenti e
				viene considerato nel caso siano già stati tentati tutti gli altri match.
				
				Si noti che se nel primo caso si aggiungesse ulteriori parametri
				dopo il carattere jolly questi verrebbero ignorati perché 
				la condizione sul carattere jolly verrebbe soddisfatta prima della
				loro valutazione.
				
				Con elenchi di parametri particolarmente complessi l'ordine
				potrebbe essere importante e si corre il rischio di avere delle
				corrispondenze che vengono mascherate da caretteri jolly dichiarati
				prima.
				Nel caso di dubbi è meglio dichiarare i match più specifici all'inzio.

            </p>
            <p>
				Ci sono casi in cui si desidera che il mock gestisca dei
				riferimenti ad oggetti piuttosto che delle copie degli stessi.
				Accade raramente, ma potrebbe capitare di dover simulare
				un oggetto che gestisce dati primitivi, come delle stringhe.
				Per esempio:
<php><![CDATA[
class Pad {
    function Pad() { }
    function &note($index) { }
}
]]></php>
                In questo caso, per impostare un riferimento nell'elenco
				dei valori di ritorno:
<php><![CDATA[
function testTaskReads() {
    $note = 'Buy books';
    $pad = new MockPad();
    $vector-><strong>returnsByReference(</strong>'note', $note, array(3)<strong>)</strong>;
    $task = new Task($pad);
    ...
}
]]></php>
				Con questa soluzione si è certi che ogni volta che viene
				invocato  <code><![CDATA[$pad->note(3)]]></code> viene
				restituito sempre il medesimo oggetto <code>$note</code>, perfino
				quando questo viene modificato.
            </p>
            <p>
				E' possibile combinare ortogonalmente i tre fattori tempo, parametri e
				uso delle copie e dei riferimenti. Per esempio:
                
<php><![CDATA[
$buy_books = 'Buy books';
$write_code = 'Write code';
$pad = new MockPad();
$vector-><strong>returnsByReferenceAt(0, 'note', $buy_books, array('*', 3));
$vector-><strong>returnsByReferenceAt(1, 'note', $write_code, array('*', 3));
]]></php>
				Questo restituisce un riferimento a <code>$buy_books</code> e
				successivamente a <code>$write_code</code>, ma solo sei i due
				paramtri risultano impostati ed il secondo è l'intero 3.
				In questo modo ogni esigenza dovrebbe risultare soddisfatta.
            </p>
            <p>
				Un ultimo caso delicato è quello di un oggetto che ne instanzia un
				altro, ovvero quello che è conosciuto come factory pattern.
                Supponiamo che una query al nostro immaginario database abbia successo
				e che venga restituito un result set nella forma di iteratore in modo
				che ad ogni chiamata del metodo <code>next()</code> dell'iteratore venga fornita una
				riga o il valore false.
				L'idea di dover simulare un comportamento simile può sembrare da incubo ma
				in realtà può essere realizzata con un mock con il meccanismi già presentati:
<php><![CDATA[
Mock::generate('DatabaseConnection');
Mock::generate('ResultIterator');

class DatabaseTest extends UnitTestCase {

    function testUserFinderReadsResultsFromDatabase() {<strong>
        $result = new MockResultIterator();
        $result->returns('next', false);
        $result->returnsAt(0, 'next', array(1, 'tom'));
        $result->returnsAt(1, 'next', array(3, 'dick'));
        $result->returnsAt(2, 'next', array(6, 'harry'));

        $connection = new MockDatabaseConnection();
        $connection->returns('selectQuery', $result);</strong>

        $finder = new UserFinder(<strong>$connection</strong>);
        $this->assertIdentical(
                $finder->findNames(),
                array('tom', 'dick', 'harry'));
    }
}
]]></php>
				Adesso solo se viene invocato il metodo <code>query()</code>
				di <code>$connection</code> viene restituito l'oggetto <code>$result</code>
				che si esaurisce la sua funzione dopo la terza chiamata a <code>next()</code>.
                Dovrebbero esserci abbastanza informazioni perché la classe
				<code>UserFinder</code> possa essere collaudata senza problemi.
				Un test molto preciso e nessun database reale tra i piedi.
            </p>
            <p>
                E' possibile ulteriormente raffinare questo test richiedendo che venga
				utilizzata la query corretta:
<php><![CDATA[
$connection->returns('selectQuery', $result, array(<strong>'select name, id from people'</strong>));
]]></php>
                Il realtà questa è una cattiva idea.
            </p>
            <p>
				Abbiamo <code>UserFinder</code> che appartiene al mondo degli oggetti
				e che comunica con le tabelle del database utilizzando un'interfaccia
				piuttosto estesa, l'intero SQL.
				Immaginamo di aver scritto molti test come questo che adesso si trovano
				a dipendere dall'esatta stringa SQL utilizzata.
				C'è la possibilità che queste query cambino in massa per ragioni non legate
				allo specifico test. Ad esempio, le regole nell'uso di apici e virgolette
				potrebbe cambiare, potrebbe essere rinominata una tabella, potrebbe venire
				aggiunta una link table e così via.
				Queste modifiche richiederebbero la riscrittura di ogni singolo test ogni volta
				che viene eseguito un refactoring, nonostante il comportamento da collaudare
				sia fondamentalmente restato inalterato.
				I test sono pensati per aiutare il refactoring, non per ostacolarlo.
                Personalmente, preferirei certamente una test suite che non faccia fallire i
				test solo per un cambio di nome di tabella.
            </p>
            <p>
                Una regola è quella di non scrivere mock di interfacce troppo complesse.
				
            </p>
            <p>
                Al contrario, ecco come appare un test completo:
<php><![CDATA[
class DatabaseTest extends UnitTestCase {<strong>
    function setUp() { ... }
    function tearDown() { ... }</strong>

    function testUserFinderReadsResultsFromDatabase() {
        $finder = new UserFinder(<strong>new DatabaseConnection()</strong>);
        $finder->add('tom');
        $finder->add('dick');
        $finder->add('harry');
        $this->assertIdentical(
                $finder->findNames(),
                array('tom', 'dick', 'harry'));
    }
}
]]></php>
				Questo collaudo è immune ai cambiamenti dello schema del db.
				Fallisce solo se si rompono le funzionalità dell'applicazione, cioè
				quello che intendevamo collaudare.
            </p>
            <p>
				Il segreto è nel codice di <code>setUp()</code> e di <code>tearDown()</code>
				sui quali fino ad ora abbiamo sorvolato.
				Questi metodi hanno il compito di ripulire le tabelle del database
				ed assicurare la correttezza dello schema.
				Realizzare questo risultato può comportare molto lavoro ma generalente 
				si dispone comunque di codice simile per svolgere il deployment.
            </p>
            <p>
				Un'area dove si ha veramente bisogno del mocking è nella simulazione
				delle anomalie.
				Supponiamo che il database cada durante il funzionamento di <code>UserFinder</code>
                
                <code>UserFinder</code> reagisce come desideriamo?
<php><![CDATA[
class DatabaseTest extends UnitTestCase {

    function testUserFinder() {
        $connection = new MockDatabaseConnection();<strong>
        $connection->throwOn('selectQuery', new TimedOut('Ouch!'));</strong>
        $alert = new MockAlerts();<strong>
        $alert->expectOnce('notify', 'Database is busy - please retry');</strong>
        $finder = new UserFinder($connection, $alert);
        $this->assertIdentical($finder->findNames(), array());
    }
}
]]></php>
				E' stato passato un oggetto <code>$alert</code> a <code>UserFinder</code>.
				Questo invierà alcuni messaggi all'interfaccia utente.
				Per poter passare il test, il finder, piuttostci che propagare 
				un'eccezione, deve scrivere un messaggio a <code>$alert</code>.
                				
				Per adesso, tutto bene.
                
            </p>
            <p>
				Come possiamo dire al mock <code>DatabaseConnection</code> di lanciare l'eccezione?
                La generiamo usando il metodo <code>throwOn</code>.
            </p>
            <p>
				Infine, cosa accade se il metodo che intendiamo simulare non esiste affatto?
				Se si tenta di impostare un valore di ritorno su un metodo che non esiste,
				SimpleTest lancia un'errore.
				Perché non usare <code>__call()</code> per simulare dinamicamente i metodi?
            </p>
            <p>
				L'uso di <code>__call</code> sugli oggetti con interfacce dinamiche
				nella implementazione corrente dei mock può essere problematico.
				E' possibile fare il mock del metodo <code>__call()</code> ma è una soluzione
				orrenda.
				Perché mail un test dovrebbe prendersi cura di tali dettagli di implementazione?
				Il test vuole solo simulare la chiamata.
            </p>
            <p>
				La soluzione a questo è di aggiungere metodi extra al mock durante
				la sua generazione.
<php><![CDATA[
<strong>Mock::generate('DatabaseConnection', 'MockDatabaseConnection', array('setOptions'));</strong>
]]></php>
				In test suite di notevoli dimensioni questo può generare problemi, dal momento
				che c'è il rischio di avere già una classe chiamata 
                <code>MockDatabaseConnection</code> priva dei metodi extra.
				Il code generator infatti non genera la versione mock di una classe se ne
				trova un'altra con lo stesso nome.
				Vedere il proprio metodo fallire perché un'altra definizione è stata
				invocata precedentemente può essere disorientante.
            </p>
            <p>
				Per gestire questa situazione, SimpleTest permette allo sviluppatore
				di scegliere liberamente il nome della nuova classe nel momento dell'aggiunta
				dei metodi extra.
<php><![CDATA[
Mock::generate('DatabaseConnection', <strong>'MyMockDatabaseConnection'</strong>, array('setOptions'));
]]></php>
				In questo esempio il mock si comporta come se <code>setOptions()</code>
				esistesse nella classe originale.
            </p>
            <p>
				Gli oggetti mock possono essere utilizzati solo all'interno dei test case
				perché inviano messaggi, come expectation, direttamente al test case.
                Lanciarli al di fuori dell'ambiente del test case provocherebbe
				un run time error non appena la prima expectation fosse invocata.
				Parleremo delle expectation più avanti.
            </p>
        </section>
        <section name="expectations" title="Mock come critici">
            <p>
				Nonostante l'approccio dei server stub riesca ad isolare i test
				dagli sconvolgimenti del mondo, questa è solo una metà dei benefici.
				E' possibile fare in modo che la classe sotto collaudo riceva
				i messaggi richiesti: ma si riesce a fargli inviare indietro quelli corretti?
				Il collaudo può diventare un vero inferno senza una libreria di mocking.
            </p>
			<p>
				Per fare un esempio, consideriamo una semplice classe <code>PageController</code>
				che gestisca il form per il pagamento con carta di credito:
                
<php><![CDATA[
class PaymentForm extends PageController {
    function __construct($alert, $payment_gateway) { ... }
    function makePayment($request) { ... }
}
]]></php>
				Questa classe utilizza un oggetto <code>PaymentGateway</code> per comunicare
				fisicamente con la banca ed un oggetto <code>Alert</code> per gestire gli errori.
				La classe comunica anche alla pagine o al template.
				E' responsabile della visualizzazione degli errori e dell'evidenziazione
				di ogni campo del form che non sia stato compilato correttamente.
            </p>
            <p>
				Il metodo che ci interessa è <code>makePayment()</code>.
				Se viene inserito un numero &quot;CVV2&quot; errato (le ultime 3 cifre
				sul retro della carta di credito) si vuole che il processo di pagamento non
				venga nemmeno iniziato e che venga visualizzato invece un errore.
				Nel test form avremo:
<php><![CDATA[
<?php
require_once('simpletest/autorun.php');
require_once('payment_form.php');
Mock::generate('Alert');
Mock::generate('PaymentGateway');

class PaymentFormFailuresShouldBeGraceful extends UnitTestCase {

    function testMissingCvv2CausesAlert() {
        $alert = new MockAlert();
        <strong>$alert->expectOnce(
                    'warn',
                    array('Missing three digit security code', 'cvv2'));</strong>
        $controller = new PaymentForm(<strong>$alert</strong>, new MockPaymentGateway());
        $controller->makePayment($this->requestWithMissingCvv2());
    }

    function requestWithMissingCvv2() { ... }
}
?>
]]></php>
				Una domanda sorge spontanea: dove sono gli assert?
            </p>
            <p>
				La chiamata a <code>expectOnce('warn', array(...))</code> indica al mock
				di attendersi una chiamata a <code>warn()</code> prima che il test termini.
				Nel momento in cui la chiamata a <code>warn()</code> viene intercettata, il mock verifica
				gli argomenti utilizzati. Se gli argomenti non corrispondono a quanto
				stabilito viene generata una failure.
				Viene generata una failure anche nel caso la chiamata non venga eseguita affatto.
            </p>
            <p>
				Il test appena visti non si milita a verificare che <code>warn</code> venga
				chiamato ma che vengano ricevuta la stringa &quot;Missing three digit security code&quot;
				ed il tag &quot;cvv2&quot;.
				Nel momento della comparazione di entrambi i parametri viene applicato
				l'equivalente di <code>assertIdentical()</code>.
            </p>
            <p>
				Nel caso non si sia interessati al messaggio, come accade nel caso
				di messaggi provenienti dall'interfaccia utente soggetti a molti cambiamenti,
				è possibile saltare il parametro con l'operatore &quot;*&quot;:
<php><![CDATA[
class PaymentFormFailuresShouldBeGraceful extends UnitTestCase {

    function testMissingCvv2CausesAlert() {
        $alert = new MockAlert();
        $alert->expectOnce('warn', array(<strong>'*'</strong>, 'cvv2'));
        $controller = new PaymentForm($alert, new MockPaymentGateway());
        $controller->makePayment($this->requestWithMissingCvv2());
    }

    function requestWithMissingCvv2() { ... }
}
]]></php>
				Possiamo rendere ancora più debole il test tralasciando l'array
				dei parametri:
<php><![CDATA[
function testMissingCvv2CausesAlert() {
    $alert = new MockAlert();
    <strong>$alert->expectOnce('warn');</strong>
    $controller = new PaymentForm($alert, new MockPaymentGateway());
    $controller->makePayment($this->requestWithMissingCvv2());
}
]]></php>
				In questo modo l'unico test che verrà effettuato è sull'invocazione
				del metodo, il che può essere un po' eccessivo in questo caso.
				Più avanti vedremo come indebolire le expectation in modo più selettivo.
            </p>
            <p>
				I test senza assert sono sia compatti che molto espressivi.
				Siccome la chiamata viene intercettata mentre arriva dall'interno dell'oggetto, in questo
				caso della classe <code>Alert</code>, non c'è il bisogno di dichiarare alcun assert sul suo
				stato.
				Non solo questo evita gli assert nei test ma anche la necessità di aggiungere
				altri accessor al codice originale.
                Nel caso ci si dovesse scoprire ad aggiungere accessor al codice, cioè quelli che
				comunemente vengono chiamati &quot;state based testing&quot;, potrebbe essere il momento di
				considerare l'uso dei mock nei propri test.
				Quest'ultimo approccio è chiamato &quot;behaviour based testing&quot; ed è normalmente considerato
				migliore rispetto all'uso degli accessor.
            </p>
            <p>
				Aggiungiamo un altro test.
				Assicuriamoci che non si riesca nemmeno a tentare un pagamento in assenza del codice CVV2:
<php><![CDATA[
class PaymentFormFailuresShouldBeGraceful extends UnitTestCase {

    function testMissingCvv2CausesAlert() { ... }

    function testNoPaymentAttemptedWithMissingCvv2() {
        $payment_gateway = new MockPaymentGateway();
        <strong>$payment_gateway->expectNever('pay');</strong>
        $controller = new PaymentForm(new MockAlert(), $payment_gateway);
        $controller->makePayment($this->requestWithMissingCvv2());
    }

    ...
}
]]></php>
				Nei test può risultare molto difficile realizzare l'assert di una condizione negativa
				ma il metodo <code>expectNever()</code> rende l'operazione semplice:
            </p>
            <p>
                <code>expectOnce()</code> e <code>expectNever()</code> sono più che sufficienti
				per la maggior parte dei test ma, occasionalmente, si potrebbe aver bisogno di
				collaudare più eventi.
				Normalmente, a vantaggio dell'usabilità, si vuole che vengano evidenziati  tutti i campi
				non compilati del form e non solo il primo.
				Allo scopo dovremmo essere in grado di eseguire chiamate multiple
				a <code>Alert::warn()</code> e non solo una:
<php><![CDATA[
function testAllRequiredFieldsHighlightedOnEmptyRequest() {
    $alert = new MockAlert();<strong>
    $alert->expectAt(0, 'warn', array('*', 'cc_number'));
    $alert->expectAt(1, 'warn', array('*', 'expiry'));
    $alert->expectAt(2, 'warn', array('*', 'cvv2'));
    $alert->expectAt(3, 'warn', array('*', 'card_holder'));
    $alert->expectAt(4, 'warn', array('*', 'address'));
    $alert->expectAt(5, 'warn', array('*', 'postcode'));
    $alert->expectAt(6, 'warn', array('*', 'country'));
    $alert->expectCallCount('warn', 7);</strong>
    $controller = new PaymentForm($alert, new MockPaymentGateway());
    $controller->makePayment($this->requestWithMissingCvv2());
}
]]></php>
				Il contatore presente in <code>expectAt()</code> rappresenta il numero
				di volte per il quale il metodo è già stato invocato.
				Qui si sta eseguendo un assert per ogni campo che verrà evidenziato.
            </p>
            <p>
				Si noti che siamo costretti a valutare anche l'ordine delle chiamate.
				SimpleTest non prevede ancora un sistema per evitare questo inconveniente
				ma lo prevederà nelle prossime versioni.
            </p>
            <p>
				Di seguito è riportato un elenco delle expectation utilizzabili su un
				oggetto mock in <a href="http://simpletest.org/">SimpleTest</a>.
				Così come per gli assert, questi metodi accettano un parametro opzionale
				con il messaggio di failure.
                <table>
                    <thead><tr><th>Expectation</th><th>Descrizione</th></tr></thead>
                    <tbody>
                        <tr>
                            <td><code>expect($method, $args)</code></td>
                            <td>Nel caso il metodo venga invocato, gli argomenti devono corrispondere a quanto dichiarato</td>
                        </tr>
                        <tr>
                            <td><code>expectAt($timing, $method, $args)</code></td>
                            <td>Gli argomenti devono corrispondere alla <code>$timing</code>-esima chiamata</td>
                        </tr>
                        <tr>
                            <td><code>expectCallCount($method, $count)</code></td>
                            <td>Il metodo deve essere invocato esattamente <code>$count</code> volte</td>
                        </tr>
                        <tr>
                            <td><code>expectMaximumCallCount($method, $count)</code></td>
                            <td>Il metodo deve essere invocato non più di <code>$count</code> volte</td>
                        </tr>
                        <tr>
                            <td><code>expectMinimumCallCount($method, $count)</code></td>
                            <td>Il metodo deve essere invocato almeno <code>$count</code> volte</td>
                        </tr>
                        <tr>
                            <td><code>expectNever($method)</code></td>
                            <td>Il metodo non deve essere mai invocato</td>
                        </tr>
                        <tr>
                            <td><code>expectOnce($method, $args)</code></td>
                            <td>Il metodo deve essere invocato una sola volta e con i parametri indicati</td>
                        </tr>
                        <tr>
                            <td><code>expectAtLeastOnce($method, $args)</code></td>
                            <td>Il metodo deve essere invocato almeno una volta e con i parametri indicati</td>
                        </tr>
                    </tbody>
                </table>
				I parametri sono:
                <dl>
                    <dt class="new_code">$method</dt>
                    <dd>La stringa con il nome del metodo al quale applicare la condizione.</dd>
                    <dt class="new_code">$args</dt>
                    <dd>
						L'elenco degli argomenti. E' possibile utilizzare i caratteri jolly allo
						stesso modo in cui si utilizzano con <code>setReturn()</code>.
                        Questo argomento è opzionale in <code>expectOnce()</code>
                        e in <code>expectAtLeastOnce()</code>.
                    </dd>
                    <dt class="new_code">$timing</dt>
                    <dd>
						L'istante in cui valutare la consizione.
						La prima chiamata inizia con 0 ed i conteggi delle chiamate ai vari
						metodi sono indipendenti tra loro.
                    </dd>
                    <dt class="new_code">$count</dt>
                    <dd>Il numero di invocazioni attese</dd>
                </dl>
            </p>
            <p>
				Nel caso si abbia una sola chiamata nel test, è bene assicurarsi
				di usare <code>expectOnce</code>.<br />
                L'uso di <code>$mocked->expectAt(0, 'method', 'args);</code>
				consertirebbe al metodo di non essere mai invocato.
				Il controllo degli argomenti ed il controllo del numero totale di chiamate 
				sono operazioni indipendenti.
				Quando si usa <code>expectAt()</code>, deve essere aggiunta la chiamata a <code>expectCallCount()</code> 
				altrimenti risulterà consentito non invocare mai il metodo.
            </p>
            <p>
				Come per gli assert nei test case, tutte le expectation accettano come terzo parametro un
				messaggio con il quale sovrascrivere il messaggio di default.
				Come nell'altro caso, inoltre, il messaggio di default può essere
				recuperato mediante &quot;%s&quot;.
            </p>
        </section>
    </content>
    <internal>
        <link>
            <a href="#what">What are mock objects?</a>
        </link>
        <link>
            <a href="#creation">Creating mock objects</a>.
        </link>
        <link>
            <a href="#expectations">Mocks as critics</a> with expectations.
        </link>
    </internal>
    <external>
        <link>
            The original
            <a href="http://www.mockobjects.com/">Mock objects</a> paper.
        </link>
        <link>
            SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
        </link>
        <link>
            SimpleTest home page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
        </link>
    </external>
    <meta>
        <keywords>
            software development,
            php programming,
            programming php,
            software development tools,
            php tutorial,
            free php scripts,
            architecture,
            php resources,
            mock objects,
            junit,
            php testing,
            unit test,
            php testing,
            jmock,
            nmock
        </keywords>
    </meta>
</page>
