Come creare test di integrazione gratuiti e scalabili?

14

Nel mio attuale progetto, mi viene difficile trovare una buona soluzione per creare test di integrazione scalabili senza effetti collaterali. Un piccolo chiarimento sulla proprietà free dell'effetto collaterale: riguarda principalmente il database; non ci dovrebbero essere cambiamenti nel database dopo che i test sono stati completati (lo stato dovrebbe essere preservato). Forse la scalabilità e la conservazione dello stato non si incontrano, ma voglio davvero spingere per una soluzione migliore.

Ecco un tipico test di integrazione (questi test toccano il livello del database):

public class OrderTests {

    List<Order> ordersToDelete = new ArrayList<Order>(); 

    public testOrderCreation() {
        Order order = new Order();
        assertTrue(order.save());
        orderToDelete.add(order);
    }

    public testOrderComparison() {
        Order order = new Order();
        Order order2 = new Order();
        assertFalse(order.isEqual(order2);
        orderToDelete.add(order);
        orderToDelete.add(order2);
    }
    // More tests

    public teardown() {
         for(Order order : ordersToDelete)
             order.delete();
    }
}

Come si può immaginare, questo approccio produce test estremamente lenti. Inoltre, se applicato a tutti i test di integrazione, sono necessari circa 5 secondi per testare solo una piccola parte del sistema. Posso immaginare che questo numero salga quando la copertura è aumentata.

Quale sarebbe un altro approccio per scrivere tali test? Un'alternativa che posso pensare è avere una specie di variabili globali (all'interno di una classe) e tutti i metodi di test condividono questa variabile. Di conseguenza, vengono creati solo pochi ordini e amp; soppressa; risultante in test più rapidi. Tuttavia, penso che questo introduce un problema più grande; i test non sono più isolati e diventa sempre più difficile da capire & analizzarli.

Potrebbe essere semplicemente che i test di integrazione non sono pensati per essere eseguiti tutte le volte che si effettuano i test unitari; quindi basse prestazioni potrebbero essere accettabili per quelli. In ogni caso, sarebbe bello sapere se qualcuno ha trovato alternative per migliorare la scalabilità.

    
posta Guven 21.10.2011 - 02:07
fonte

5 risposte

6

Cerca di utilizzare Hypersonic o un altro DB in memoria per il test dell'unità. Non solo i test verranno eseguiti più velocemente, ma gli effetti collaterali non sono rilevanti. (Il rollback delle transazioni dopo ogni test rende anche possibile eseguire molti test sulla stessa istanza)

Questo ti costringerà anche a creare mockup di dati, il che è una buona cosa IMO, poiché significa che qualcosa che si verifica sul database di produzione non può iniziare in modo inspiegabile fallendo i tuoi test, E ti dà un punto di partenza per ciò che un " installazione di un database pulito ", sarebbe utile se è necessario distribuire improvvisamente una nuova istanza dell'applicazione senza connessione al sito di produzione esistente.

Sì, io uso questo metodo da solo, e sì è stato un PITA a impostare la prima volta, ma è più che ripagato da solo nella vita del progetto che sto per completare. Ci sono anche una serie di strumenti che aiutano con i mockup di dati.

    
risposta data 21.10.2011 - 03:48
fonte
3

Questo è l'eterno problema che tutti affrontano durante la scrittura dei test di integrazione.

La soluzione ideale, in particolare se stai testando in produzione, è l'apertura di una transazione in fase di configurazione e la riattivazione in teardown. Penso che questo dovrebbe soddisfare le tue esigenze.

Dove non è possibile, ad esempio dove stai testando l'app dal livello client, un'altra soluzione è usare un DB su una macchina virtuale e fare uno snapshot nel setup e tornare ad esso in teardown ( non richiede tutto il tempo che ci si potrebbe aspettare).

    
risposta data 21.10.2011 - 03:14
fonte
3

I test di integrazione dovrebbero sempre essere eseguiti rispetto all'impostazione di produzione. Nel tuo caso significa che dovresti avere lo stesso database e server delle applicazioni. Ovviamente, per motivi di prestazioni, potresti decidere di utilizzare un DB in memoria.

Ciò che non dovresti mai fare è estendere l'ambito della tua transazione. Alcune persone hanno suggerito di assumere il controllo della transazione e di eseguire il rollback dopo i test. Quando fai questo, tutte le entità (supponendo che tu stia usando l'APP) rimarranno attaccate al contesto di persistenza durante l'esecuzione del test. Ciò potrebbe causare alcuni bug molto sgradevoli che sono molto difficili da trovare .

Invece, dovresti cancellare il database manualmente dopo ogni test attraverso una libreria come JPAUnit o simile a < a href="http://bripkens.de/blog/2010/12/clear-database-java-jdbc/"> questo approccio (cancella tutte le tabelle usando JDBC).

A causa dei problemi di prestazioni, non dovresti eseguire i test di integrazione su ogni build. Lascia che il tuo server di integrazione continui a farlo. Se utilizzi Maven, potresti utilizzare il plug-in failsafe che ti consente di separare i test in test di unità e integrazione.

Inoltre, non dovresti prendere in giro niente. Ricorda che sei un test di integrazione, ovvero un comportamento di test all'interno dell'ambiente di esecuzione in fase di esecuzione.

    
risposta data 21.10.2011 - 21:11
fonte
2

Sulla scalabilità

Ho avuto questo problema alcune volte in passato, che i test di integrazione richiedevano troppo tempo per essere eseguiti e non erano pratici per un singolo sviluppatore a funzionare continuamente in un ciclo di feedback limitato. Alcune strategie per far fronte a questo sono:

  • Scrivi meno test di integrazione - se hai una buona copertura con i test unitari nel sistema, i test di integrazione dovrebbero essere più focalizzati su (a) problemi di integrazione, su come i diversi componenti lavorano insieme. Sono più simili ai fumogeni, che cercano solo di vedere se il sistema funziona ancora nel suo complesso. Quindi, idealmente, i test unitari coprono la maggior parte delle parti funzionali dell'applicazione, ei test di integrazione controllano solo in che modo queste parti interagiscono tra loro. Non hai bisogno di un'ampia copertura dei percorsi logici qui, solo alcuni percorsi critici attraverso il sistema.
  • Esegui solo un sottoinsieme dei test alla volta - come singolo sviluppatore che lavora su alcune funzionalità, di solito hai un senso per cui sono necessari test per coprire tale funzionalità. Esegui solo quei test che hanno senso per coprire le tue modifiche. I framework come JUnit ti permettono di incontri di gruppo in un categoria . Crea i raggruppamenti che consentono la migliore copertura per ogni funzione che hai. Ovviamente, a un certo punto, vuoi ancora eseguire tutti i test di integrazione, magari prima di passare al sistema di controllo del codice sorgente e sicuramente al server di integrazione continua.
  • Ottimizza il sistema - I test di integrazione accoppiati con alcuni test delle prestazioni potrebbero fornirti l'input necessario per ottimizzare le parti lente del sistema, in modo che i test possano essere eseguiti più rapidamente. Ciò potrebbe aiutare a scoprire gli indici necessari nel database, le interfacce chatty tra i sottosistemi o altri colli di bottiglia nelle prestazioni che richiedono l'indirizzamento.
  • Esegui i tuoi test in parallelo - Se hai un buon raggruppamento di test ortogonali, puoi provare a eseguirli in parallelo . Sii attento al requisito ortogonale che ho menzionato, però, non vuoi che i tuoi test si calpestino l'un l'altro.

Prova a combinare queste tecniche per ottenere un maggiore effetto.

    
risposta data 21.10.2011 - 17:48
fonte
2

A scopo di test, abbiamo utilizzato una distribuzione basata su file di un database SQLite (basta copiare una risorsa). Questo è stato fatto in modo da poter testare anche le migrazioni dello schema. Per quanto ne so, le modifiche allo schema non sono transazionali, quindi non verranno ripristinate dopo aver effettuato una transazione. Inoltre, non dover fare affidamento sul supporto delle transazioni per l'impostazione del test consente di verificare correttamente il comportamento delle transazioni dall'applicazione.

    
risposta data 21.10.2011 - 21:19
fonte

Leggi altre domande sui tag