Database non transazionale e test di integrazione

8

Un problema che ritengo di incontrare con i miei test di integrazione sta avendo più test che accedono allo stesso database. Anche se questo non è un problema ora, so che qui abbiamo più applicazioni che accedono allo stesso database e sto solo cercando di pensare a un modo per prevenire questo problema prima che accada.

Un'idea che ho visto molto sta usando le transazioni. All'avvio si avvia una transazione e quindi nel teardown si esegue il rollback della transazione. Ciò significa che più test accedono alle stesse tabelle del database e non si influenzano a vicenda, il che è ottimo. Il problema che ho è che nel mio caso, l'85-95% delle tabelle con cui sto lavorando in MySQL sono MyISAM che non supportano le transazioni.

Ci sono dei modi per aggirare i motori di memorizzazione che non supportano la transazione, ma consentono comunque a più test di accedere alle stesse tabelle senza che si influenzino a vicenda? Da quanto ho sentito, il ruby on rails testing framework usa le transazioni in questo modo, come aggirano questo problema (o loro)?

    
posta ryanzec 16.08.2011 - 20:37
fonte

3 risposte

3

Nella mia azienda, c'era questo dibattito: la persistenza è un grosso problema per i test.

Ci sono alcuni hack che ti metteranno a metà strada. Abbiamo deciso di non perdere il nostro tempo con loro:

  • utilizzando Transazioni che esegui il rollback . Ciò fallisce come:
    • A volte apri una transazione isolata (all'interno di una più generale), quindi è stata chiusa prima che il codice di prova possa controllarla
    • Non puoi testare la tua vera persistenza. (Cosa succede quando un test chiude una transazione ed esegue un'interrogazione complessa interessata da quei dati in una transazione diversa oppure salva i dati e li carica di nuovo in seguito.)
    • Non puoi testare completamente il tuo codice (solo i livelli sotto il livello di transazione, non abbastanza buono se consideri gli svantaggi dei test di integrazione).
  • utilizzando un database pulito di recente per ogni test . Anche questo fallisce come:
    • la nostra suite di test arriverà presto a qualche migliaio di test (abbiamo grandi team). L'impostazione di un nuovo database richiede al massimo dei minuti (poiché abbiamo molti cataloghi e parametri che fanno parte di ogni versione). La nostra suite di test impiegherebbe presto mesi e non ci resta che attendere alcuni giorni.
    • avremmo bisogno di un'istanza di database specifica per ogni sviluppatore o ogni macchina e abbiamo un criterio per avviare solo un test alla volta. Abbiamo bisogno di utilizzare Oracle 11 per verificare che le nostre query siano soddisfacenti, sarebbe troppo costoso (licenze Oracle).
  • pulizia accurata dopo ogni test (i framework di test forniscono hook per il codice in esecuzione dopo un test). Ciò fallisce come:
    • è molto costoso mantenere una corrispondenza perfetta tra il codice che does e il test che undoes . Non appena la partita non è perfetta, i sintomi non sono chiari, un test potrebbe fallire pur essendo alcune centinaia di righe dopo; o un test che dovrebbe fallire potrebbe passare erroneamente.
    • ci sono sempre casi limite in cui la pulizia non è corretta (arresto anomalo della macchina o del software?). Ciò lascia uno stato sconosciuto per le esecuzioni successive.
    • quando un test mostra un errore, lo stato del database sarebbe un'informazione essenziale, ma andrebbe perso (perché puliamo prima del prossimo test, per finire la suite di test e mostrare allo sviluppatore tutte le informazioni).

Quindi siamo passati a una politica che sapevamo essere valida:

  • hanno Test unitari automatici per i nostri requisiti :
    • se necessario, mock accessi al database (ma di solito non abbiamo bisogno di JMock, potrei spiegare il nostro design se richiesto).
    • I test
    • vengono eseguiti con una frequenza superiore a 100 al secondo
    • I test
    • sono veloci da scrivere, brevi e chiari da leggere.
    • I test
    • non dipendono da nessuno stato persistente, quindi sono completamente isolati l'uno dall'altro naturalmente (non è necessario un meccanismo complesso)
  • test integrazione con il database separatamente (ovvero richiesta su richiesta, non integrata con la logica dell'applicazione).
    • abbiamo preso in considerazione l'automazione di tale compito, ma mi è sembrato troppo costoso (vedi la parte precedente del mio post)
    • così abbiamo tenuto il manuale di questi test: ogni sviluppatore che modifica una query dovrebbe testarlo di nuovo nel database (che di solito è parte dei suoi test end-to-end attraverso l'interfaccia utente).
risposta data 29.08.2011 - 22:39
fonte
2

Anche se non hai "transazioni", nel senso di T-SQL, dovresti comunque cercare di rendere le tue transazioni (nel senso generale del termine) atomiche. I test non devono fare affidamento su ciascuno e dovrebbero essere reversibili. Se non si dispone di alcun rollback ufficiale o ambito di transazione, è possibile che si desideri crearne uno proprio. Ad esempio, è possibile che i test dell'unità eseguano una ripulitura, in cui vengano eliminati tutti i record creati nel test.

    
risposta data 16.08.2011 - 20:51
fonte
0

Basta che ogni utente o ogni esecuzione esegua l'override del database utilizzato. Questo è quello che facciamo al lavoro. Quindi non hai mai problemi con 2 test simultanei che interferiscono tra loro.

Ogni esecuzione di test crea il db up con le migrazioni, popola il db con le fixture e poi le abbassa all'indietro alla fine.

Se il DBMS supporta le transazioni, lo usiamo come ottimizzazione per l'installazione iniziale e il teardown. Sono opzionali, anche se il test può durare un po 'senza. Come sempre YYMV.

Nessun problema, niente muss.

    
risposta data 30.08.2011 - 00:07
fonte

Leggi altre domande sui tag