2011-12-10 16 views
14

Quali sono alcune best practice/principi da seguire, oltre a quelli consigliati sul sito dbunit effettivo, che possono velocizzare notevolmente i test e mantenerli mantenibili? Desidero un library like factory girl per java, ma non sembra possibile a causa della tipizzazione statica.best practice dbunit per le prestazioni

Il mio attuale pensiero è di avere 1 set di dati xml per classe di test a questo punto - forse condivido alcuni di questi, e forse no. Mentre alcuni dati di test possono essere duplicati in serie di dati, trovo troppo difficile mantenere set di dati condivisi su 3000 test di unità/integrazione - e ho ancora molto da fare.

Apprezzerebbe qualsiasi principio da seguire che porti a test che si comportano bene e di facile manutenzione.

+0

La domanda è: per le prestazioni, ma la vera preoccupazione sembra essere "renderli mantenibili". IMHO, dovresti concentrarti assolutamente sulla manutenibilità e aumentare le prestazioni aggiungendo più potenza di calcolo. – Jayan

+2

Tieni presente che se si utilizzano più set di dati di piccole dimensioni con DBUnit, è possibile incorrere in un brutto problema di errori casuali. Ho scritto un [post sul blog che spiega perché e come aggirarlo] (http://www.andrewspencer.net/2011/solve-foreign-key-problems-in-dbunit-test-data/). –

+0

Se desideri una Factory Girl per Java, dai uno sguardo a https://github.com/mguymon/model-citizen – mguymon

risposta

8

In uno dei miei precedenti incarichi abbiamo avuto centinaia di test di integrazione che coinvolgono set di dati, anche se non in DBUnit — l'ambiente di test è stato scritto da zero, come è stata una società molto grande che può permettersi questo tipo di cose.

I set di dati erano organizzati in ordine gerarchico. Il sistema in prova consisteva in pochi (5-10) moduli e i dati di test seguivano quel modello. Uno script di test di unità si presentava così:

include(../../masterDataSet.txt) 
include(../moduleDataSet.txt) 

# unit-specific test data 
someProperty=someData 

I nomi delle proprietà sono stati mappati direttamente ai record DB da qualche bizzarro strumento non riesco a ricordare.

Lo stesso modello può essere applicato ai test DBUnit. Nel set di dati master è possibile inserire i record sempre come — come dizionari, caricamento iniziale del database, come se dovesse essere installato da zero.

Nel set di dati del modulo si inseriscono record di casi di test della maggior parte dei test in un modulo; Non credo che un tuo test medio coinvolga tutte le tue 70 tabelle del database, vero? È sicuramente necessario disporre di alcuni gruppi di funzionalità che potrebbero costituire un modulo, anche se l'applicazione è monolitica. Prova ad organizzare i dati di test a livello di modulo attorno ad esso.

Infine, al livello di test, si modifica solo il set di test con un numero minimo di record necessari per questo test particolare.

Questo approccio ha l'enorme vantaggio dell'apprendimento; perché ci sono pochi file di dati, in tempo, in realtà inizi a memorizzarli. Invece di vedere centinaia di grandi insiemi di dati che differiscono solo da dettagli non percepibili (che devi scoprire ogni volta che torni a un test dopo un po '), puoi facilmente capire quanto siano diversi i due set di dati.

Una parola sulla prestazione alla fine. Sul mio 2.4 GHz 2-nucleo WinXP macchina un test DBUnit coinvolge:

  • cadere 14 tavoli,
  • creazione 14 tavoli,
  • inserimento ca. 100 record,
  • eseguire la logica di test,

richiederà 1-3 secondi. I registri mostrano che le prime 3 operazioni richiedono meno di un secondo, la maggior parte del tempo di test viene consumata da Spring. Questa logica viene eseguita da ciascun test, per evitare le dipendenze degli ordini di test. Tutto funziona in una VM con Derby incorporato, questo è probabilmente il motivo per cui è così veloce.

EDIT: Penso che i set di dati DBUnit XML non supportano l'inclusione di altri file di test, può essere superato utilizzando una classe base per tutti i test di integrazione, ad esempio:

public class AbstractITest { 

    @Before 
    public void setUp() throws Exception { 
     // 
     // drop and recreate tables here if needed; we use 
     // Spring's SimpleJdbcTemplate executing drop/create SQL 
     // 
     IDataSet masterDataSet = new FlatXmlDataSetBuilder().build("file://masterDataSet.xml"); 
     DatabaseOperation.CLEAN_INSERT.execute(dbUnitConnection, dataSet); 
    } 
} 

public class AbstractModuleITest extends AbstractITest { 

    @Before 
    public void setUp() throws Exception { 
     super.setUp(); 
     IDataSet moduleDataSet = new FlatXmlDataSetBuilder().build("file://moduleDataSet.xml"); 
     DatabaseOperation.CLEAN_INSERT.execute(dbUnitConnection, moduleDataSet); 
    } 
} 

public class SomeITest extends AbstractModuleITest { 
    // The "setUp()" routine only here if needed, remember to call super.setUp(). 

    @Test 
    public void someTest() { ... } 
} 
+0

Amo questa idea. Scoprirò se dbunit supporta questo genere di cose. – egervari

+0

@egervari I set di dati XML di DBUnit probabilmente non supportano questo direttamente; vedi la mia modifica. – MaDa

+0

Mi piace molto la tua idea. Penso che creare un set di dati master completo di informazioni sul dizionario sia fantastico. Tuttavia, non sono un fan dei set di dati del modulo. Penso che sia facile raggruppare i test in moduli basati su dati comuni oggi, ma questi potrebbero cambiare in futuro. Creare una dipendenza da un set di dati del modulo sembra un enorme mal di testa se dovessi cambiare il tuo progetto e non ne vale la pena. Potevo vedere dove avrebbe funzionato comunque. Immagino che dipenda davvero dal tuo modello di dati. – bheussler

2

La raccomandazione in Junit nell'Azione 2e non è in realtà di creare troppi set di dati (come uno per classe di test), ma appena sufficiente considerato come mantenibile. Ad eccezione di alcuni casi eccezionali, ho trovato possibile utilizzare un set di dati master per la maggior parte dei test unitari e set di dati individuali per i test di integrazione. Limitare l'utilizzo di ExpectedDataSets è anche un'opzione.

Inoltre, ho utilizzato Unitils in combinazione con dbunit per semplificare alcune delle impostazioni e il caricamento dei dati di test, quindi è consigliabile considerarlo appropriato.

+1

Penso che il libro sia sbagliato se si tratta di una raccomandazione. Quando si dispone di un database con 70 tabelle e si hanno così tanti campi booleani diversi su flag, tonnellate di criteri di ricerca da testare e su e su ... cambiare 1 riga può causare una massiccia quantità di test da interrompere. Questo è male, e penso che sia una perdita di tempo. Forse usare un pattern builder nel codice, e poi salvarli nel database con cascate è la risposta. Non ne sono sicuro. – egervari

+0

Chiarimento: l'utilizzo di un set di dati master unico per la maggior parte dei test di unità è ciò che ho scelto che faccio in quella specifica situazione. Il libro consiglia di mantenere solo il numero di set di dati che si è pronti a mantenere, quindi invece di 1 per ogni classe/tabella, è possibile considerare un rapporto meno rigoroso. – prusswan

+0

Il mio pensiero attuale è che non sarebbe 1: 1, ma almeno il 50% dei test sarebbe 1: 1 e il resto li condividerebbe. Poiché la mia applicazione diventa sempre più complessa, ho bisogno di un minore accoppiamento con i set di dati. Ho 5 set di dati che creano 1 database al momento - e ogni test utilizza da 1 a 5 set di dati. È progettato per funzionare come 1 database. Penso che questo sia stato un errore. Mi sta conducendo lungo un percorso di dipendenza da test di inferno. – egervari