Diversi metodi di test
Per prima cosa, definisci cosa stai facendo: unit test o test di integrazione . Il numero di livelli è irrilevante per i test unitari poiché è molto probabile che si verifichi solo una classe. Il resto lo prendi in giro. Per i test di integrazione è inevitabile testare più livelli. Se disponi di buoni test unitari, il trucco è rendere i test di integrazione non troppo complessi.
Se i test unitari sono validi, non è necessario ripetere i test di tutti i dettagli quando si eseguono i test di integrazione.
I termini che utilizziamo dipendono leggermente dalla piattaforma, ma puoi trovarli in quasi tutte le piattaforme di test / sviluppo:
Esempio di applicazione
A seconda della tecnologia utilizzata, i nomi potrebbero differire, ma lo userò come esempio:
Se si dispone di una semplice applicazione CRUD con modello Prodotto, ProductsController e una vista indice che genera una tabella HTML con prodotti:
Il risultato finale dell'applicazione mostra una tabella HTML con un elenco di tutti i prodotti attivi.
Test unitari
Modello
Il modello che puoi testare abbastanza facilmente. Esistono diversi metodi per farlo; usiamo infissi. Penso che sia quello che tu chiami "set di dati falsi". Quindi, prima di eseguire ogni test, creiamo la tabella e inseriamo i dati originali. La maggior parte delle piattaforme ha metodi per questo. Ad esempio, nella classe di test, un metodo setUp () che viene eseguito prima di ogni test.
Quindi eseguiamo il nostro test, ad esempio: testGetAllActive products.
Quindi testiamo direttamente su un database di test. Non deridiamo l'origine dati; lo facciamo sempre lo stesso. Questo ci consente ad esempio di testare con una nuova versione del database, e sorgeranno eventuali problemi di query.
Nel mondo reale non puoi sempre seguire la responsabilità singola al 100% . Se vuoi farlo ancora meglio, potresti usare un'origine dati che prendi in giro. Per noi (usiamo un ORM) che sembra testare la tecnologia già esistente. Inoltre, i test diventano molto più complessi e in realtà non verificano le query. Quindi continuiamo così.
I dati hard coded vengono memorizzati separatamente nelle fixture. Quindi il dispositivo è come un file SQL con un'istruzione create table e inserisce i record che usiamo. Li manteniamo piccoli a meno che non ci sia una reale necessità di testare con molti record.
class ProductModel {
public function getAllActive() {
return $this->find('all', array('conditions' => array('active' => 1)));
}
}
controllore
Il controller ha bisogno di più lavoro, perché non vogliamo testare il modello con esso. Quindi quello che facciamo è deridere il modello. Ciò significa: testiamo il metodo index () che dovrebbe restituire un elenco di record.
Quindi deridiamo il metodo del modello getAllActive () e aggiungiamo dati fissi in esso (ad esempio due record). Ora testiamo i dati che il controller invia alla vista e confrontiamo se recuperiamo davvero quei due record.
function testProductIndexLoggedIn() {
$this->setLoggedIn();
$this->ProductsController->mock('ProductModel', 'index', function(return array(your records) ));
$result=$this->ProductsController->index();
$this->assertEquals(2, count($result['products']));
}
È abbastanza. Cerchiamo di aggiungere meno funzionalità al controller perché ciò rende difficili i test. Ma ovviamente c'è sempre del codice. Ad esempio, testiamo requisiti come: Mostra quei due record solo se hai effettuato l'accesso.
Quindi, il controller ha bisogno di una finta normalmente e di una piccola parte di dati hardcoded. Per un sistema di accesso forse un altro. Nel nostro test abbiamo un metodo helper per questo: setLoggedIn (). Ciò semplifica il test con login o senza login.
class ProductsController {
public function index() {
if($this->loggedIn()) {
$this->set('products', $this->ProductModel->getAllActive());
}
}
}
Visualizzazioni
Il test delle viste è difficile. Innanzitutto separiamo la logica che si ripete. Lo inseriamo in Helpers e testiamo rigorosamente quelle classi. Ci aspettiamo sempre lo stesso risultato. Ad esempio, generateHtmlTableFromArray ().
Quindi abbiamo alcune viste specifiche del progetto. Non li testiamo. Non è davvero desiderabile testare l'unità. Li conserviamo per i test di integrazione. Poiché abbiamo preso gran parte del codice nelle viste, qui abbiamo un rischio inferiore.
Se inizi a testare quelli che probabilmente hai bisogno di cambiare i tuoi test ogni volta che cambi un pezzo di HTML che non è utile per la maggior parte dei progetti.
echo $this->tableHelper->generateHtmlTableFromArray($products);
Test d'integrazione
A seconda della tua piattaforma qui puoi lavorare con le storie degli utenti, ecc. Potrebbe essere webbased come Selenium o altre soluzioni comparabili.
Generalmente cariciamo semplicemente il database con i dispositivi e affermiamo quali dati dovrebbero essere disponibili. Per i test di integrazione completi utilizziamo generalmente requisiti molto globali. Quindi: impostare il prodotto su attivo e quindi verificare se il prodotto diventa disponibile.
Non testiamo di nuovo tutto, ad esempio se sono disponibili i campi giusti. Testiamo qui i requisiti più grandi. Dal momento che non vogliamo duplicare i nostri test dal controller o dalla vista. Se qualcosa è veramente una parte chiave / fondamentale della tua applicazione o per motivi di sicurezza (controlla la password NON è disponibile), li aggiungiamo per assicurarci che sia giusto.
I dati hard coded sono memorizzati nelle fixture.
function testIntegrationProductIndexLoggedIn() {
$this->setLoggedIn();
$result=$this->request('products/index');
$expected='<table';
$this->assertContains($expected, $result);
// Some content from the fixture record
$expected='<td>Product 1 name</td>';
$this->assertContains($expected, $result);
}