2009-08-25 22 views
16

Il nostro team ha centinaia di test di integrazione che colpiscono un database e verificano i risultati. Ho due classi base per tutti i test di integrazione, uno per i test di sola lettura e uno per i test di creazione/aggiornamento/eliminazione. La classe base di solo recupero rigenera il database durante TestFixtureSetup in modo che venga eseguito solo una volta per classe di test. La classe base CUD rigenera il database prima di ogni test. Ogni classe di repository ha una propria classe di test corrispondente.Migliori pratiche di test di integrazione

Come potete immaginare, l'intera operazione richiede un po 'di tempo (si avvicina a 7-8 minuti per correre e crescere rapidamente). Avere eseguito questo come parte del nostro CI (CruiseControl.Net) non è un problema, ma l'esecuzione locale richiede molto tempo e proibisce davvero di eseguirli prima di eseguire il codice.

La mia domanda è: esistono delle best practice per accelerare l'esecuzione di questi tipi di test di integrazione?

Non riesco a eseguirli in memoria (a la sqlite) perché utilizziamo alcune funzionalità specifiche del database (colonne calcolate, ecc.) Che non sono supportate in sqlite.

Inoltre, l'intero team deve essere in grado di eseguirli, quindi eseguirli su un'istanza locale di SQL Server Express o qualcosa potrebbe essere soggetto a errori a meno che le stringhe di connessione non siano tutte uguali per tali istanze.

Come stai ottenendo questo nel tuo negozio e cosa funziona bene?

Grazie!

risposta

5

Sono uno sviluppatore Java ma ho affrontato un problema simile. Ho scoperto che l'esecuzione di un'istanza di database locale funziona bene a causa della velocità (nessun dato da inviare tramite la rete) e perché in questo modo non si ha conflitto sul database di test di integrazione.

L'approccio generale che usiamo per risolvere questo problema è impostare gli script di compilazione per leggere le stringhe di connessione del database da un file di configurazione e quindi impostare un file per ambiente. Ad esempio, un file per WORKSTATION, un altro per CI. Quindi si impostano gli script di compilazione per leggere il file di configurazione in base all'ambiente specificato. Quindi le build in esecuzione su una workstation sviluppatore vengono eseguite utilizzando la configurazione WORKSTATION e le build in esecuzione nell'ambiente CI utilizzano le impostazioni dell'elemento della configurazione.

Aiuta enormemente anche la possibilità di creare l'intero schema del database da un singolo script, in modo che ogni sviluppatore possa rapidamente impostare un database locale per il test. È anche possibile estendere questo concetto al livello successivo e aggiungere lo script di installazione del database al processo di compilazione, in modo che l'intera configurazione del database possa essere sottoposta a script per tenere il passo con le modifiche nello schema del database.

11

in NUnit è possibile decorare le vostre classi di test (o metodi) con un attributo esempio:

[Category("Integration")] 
public class SomeTestFixture{ 
    ... 
} 
[Category("Unit")] 
public class SomeOtherTestFixture{ 
    ... 
} 

È quindi possibile stabilire nel processo di generazione sul server che tutte le categorie vengono correre e basta richiedere che gli sviluppatori eseguire un sottoinsieme delle categorie di test disponibili. Le categorie che devono eseguire dipenderanno da cose che capirai meglio di quanto farò. Ma il succo è che sono in grado di testare a livello di unità e il server gestisce i test di integrazione.

+1

+1 è più o meno quello che facciamo nel mio lavoro. Sul nostro CIS, i test unitari eseguono ogni checkin e test di integrazione una volta al giorno. – mezoid

+2

dove lavoro eseguiamo i test di integrazione su ogni build. più frequentemente esegui i test di integrazione, meglio è. –

+1

@Ken_Liu - di sicuro. Spesso si tratta di bilanciare i cicli di CPU disponibili sul server CI con il numero di commit per momento. Questo varierà per ogni team di sviluppo/ambiente. – grenade

3

Avete effettuato misurazioni (utilizzando timer o simili) per determinare dove i test trascorrono la maggior parte del loro tempo?

Se si sa già che la ricreazione del database è il motivo per cui richiedono un approccio diverso, è necessario rigenerare il database una sola volta e utilizzare le transazioni per conservare lo stato tra i test.Ogni test di tipo CUD avvia una transazione in fase di configurazione ed esegue un rollback in teardown. Ciò può ridurre in modo significativo il tempo speso per l'installazione del database per ciascun test poiché un rollback della transazione è più economico di una ricreazione completa del database.

+0

Sì, ho già visto questa idea, ma cosa succede se parte del codice che si prova usa la transazione stessa (ricordate, questi sono test di integrazione)? Allora tutto si spezzerà, quindi non penso che questo sia pratico in generale. – sleske

+1

Se stai facendo una gestione esplicita delle transazioni all'interno dei tuoi metodi hai assolutamente ragione. Questo approccio funziona meglio nei casi in cui si utilizzano aspetti o un proxy per gestire le transazioni. Abbiamo utilizzato questo approccio in un progetto basato su Spring e l'impostazione del test di integrazione ha sostituito il proxy con la transazione gestita unit test. Ha funzionato come un fascino. – henrik

3

Abbiamo un'istanza di SQL Server Express con la stessa definizione di DB in esecuzione per ogni macchina di sviluppo come parte dell'ambiente dev. Con l'autenticazione di Windows le stringhe di connessione sono stabili - nessun nome utente/password nella stringa.

Quello che vorremmo davvero fare, ma non ancora, è vedere se possiamo far funzionare il nostro sistema su SQL Server Compact Edition, che è come SQLite con il motore di SQL Server. Quindi potremmo eseguirli in memoria, e possibilmente anche in parallelo (con più processi).

+0

mmm SQL Compact. che * sarebbe * dolce! – grenade

+0

mi piace l'idea, sicuramente! –

13

Tenere separati i test veloce (unità) e lento (integrazione), in modo da poterli eseguire separatamente. Utilizzare qualsiasi metodo per raggruppare/classificare i test è fornito dal framework di test. Se il framework di testing non supporta il raggruppamento dei test, spostare i test di integrazione in un modulo separato che ha solo test di integrazione.

I test rapidi dovrebbero richiedere solo alcuni secondi per eseguirli tutti e dovrebbero avere una copertura di codice elevata. Questo tipo di test consente agli sviluppatori di refactoring spietatamente, perché possono fare un piccolo cambiamento ed eseguire tutti i test ed essere molto fiduciosi che il cambiamento non ha infranto nulla.

I test lenti possono richiedere molti minuti e faranno in modo che i singoli componenti funzionino correttamente. Quando gli sviluppatori apportano modifiche che potrebbero interrompere qualcosa che viene testato dai test di integrazione ma non dai test di unità, devono eseguire tali test di integrazione prima di eseguire il commit. In caso contrario, i test lenti vengono eseguiti dal server CI.

Problemi correlati