Perché utilizzare il database in memoria per i test di integrazione?

17

Sono davvero confuso quando vedo molta implementazione del database in memoria utilizzata per i test, perché ho anche sentito molto dalle migliori pratiche di test di integrazione che l'ambiente che esegue il test dovrebbe essere il più simile possibile all'ambiente di produzione, incluso sistema operativo, libreria, motore di database, ecc.

Cosa mi manca qui?

    
posta dnang 09.10.2013 - 17:35
fonte

5 risposte

17

In una tipica situazione di sviluppo del software, i test vengono utilizzati in due punti: durante lo sviluppo e prima di spostare il prodotto lungo la catena di sviluppo.

La prima situazione, l'esecuzione di test durante lo sviluppo, serve obiettivi a breve termine: definire compiti (come in TDD: scrivere un test non riuscito, quindi farlo passare), prevenire regressioni, assicurandosi che le tue modifiche non si rompano nient'altro, ecc. Tali test devono essere estremamente rapidi: idealmente, l'intera suite di test viene eseguita in meno di 5 secondi e puoi eseguirla in loop vicino all'IDE o all'editor di testo mentre esegui il codice. Qualsiasi regressione introdotta verrà visualizzata in pochi secondi. Le prove veloci sono più importanti in questa fase rispetto al 100% di regressioni e bug, e dal momento che è impraticabile (o addirittura impossibile) svilupparsi su copie esatte dei sistemi di produzione, lo sforzo richiesto per ottenere test perfetti qui non vale la pena esso. L'utilizzo di database in memoria è un compromesso: non sono copie esatte del sistema di produzione, ma aiutano a mantenere le corse di prova al di sotto del limite di 5 secondi; se la scelta è tra una configurazione del database leggermente diversa per i miei test relativi al database e nessun test, so cosa scelgo.

La seconda situazione, spostando il codice lungo la catena di sviluppo, tuttavia richiede richiede test approfonditi. Dal momento che possiamo (e dovremmo) automatizzare questa parte del processo di sviluppo, possiamo permetterci test molto più lenti - anche se una prova completa richiede ore, programmare una build notturna significa comunque avere sempre un'immagine accurata della base di codice di ieri. Simulare l'ambiente di produzione nel modo più preciso possibile è importante ora, ma possiamo permettercelo. Quindi non facciamo il compromesso del database in-memory: installiamo la stessa identica versione dello stesso DBMS dei sistemi di produzione e, se possibile, lo riempiamo con i dati di produzione effettivi prima che inizi il test.

    
risposta data 09.10.2013 - 22:25
fonte
5

Suppongo che sia una velocità di scambio / adattamento all'ambiente. I test dovrebbero essere eseguiti spesso, e questo significa che devono essere veloci. Soprattutto test di unità, che non dovrebbero richiedere più di qualche secondo.

I test di integrazione saranno più lenti, ma quando sono veloci puoi eseguirli più spesso. Ad esempio, prima di ogni commit. Certo, non è completo come un ambiente completo, ma almeno si sta testando il livello di mappatura, l'SQL generato, come la parte si parla, ecc. Nel caso di database costosi si garantisce anche che si don ' t necessario acquistare una licenza per tutti Potresti riscontrare più errori che coprono il 90% del codice con test eseguiti una volta all'ora che coprono il 100% del test del codice una volta al giorno o il peggiore, settimana.

Detto questo, ovviamente è necessario testare il database reale e un ambiente completamente integrato. Non è possibile eseguire questi test più spesso, ma dal momento che il test precedente ti ha già dato la certezza, tutto ciò che rimane è un bizzarro bug specifico della piattaforma.

    
risposta data 09.10.2013 - 17:57
fonte
2

Per fare semplici test, il mocking del livello di accesso al database è perfettamente accettabile. Chiama getName() , chiama il DAO che è stato deriso e restituisce "John" come nome e "Smith" come cognome, li assembla e tutto è perfetto. Non c'è bisogno di testare in pratica un database lì.

Le cose diventano un po 'più quando la logica diventa un po' più complessa. Cosa succede se hai un metodo "createOrUpdateUser (...)". Se prendi in giro il database, puoi verificare che un determinato metodo sia stato chiamato una volta con un determinato parametro quando la simulazione non restituisce alcun oggetto e un metodo diverso viene richiamato sul database quando restituisce un oggetto esistente. Questo inizia ad arrivare a quella linea fuzzy dove potrebbe essere più facile (specialmente se fosse già lì) per far ruotare un database specializzato nella memoria e testare quel codice con dati preconfigurati.

In un codice reale su cui ho lavorato (punto di vendita), avevamo un metodo resumeSuspededTransaction(...) . Ciò estrarrà la transazione dal database in un oggetto (e i suoi componenti) e aggiornerà il database. L'abbiamo preso in giro e un bug si nasconde nel codice da qualche parte con la serializzazione e la deserializzazione dei dati che vanno nel database (abbiamo cambiato un tipo che è stato serializzato in modo diverso sul database).

Il mock non ci ha mostrato il bug perché stava restituendo il suo percorso felice: serializza la transazione, la memorizza nella simulazione, deserializza la simulazione, verifica che siano uguali. Tuttavia, quando serializzi un oggetto con uno zero iniziale nel database, questo è stato rilasciato e quindi ricombinato su una stringa senza zeri. Abbiamo rilevato il bug senza il database attraverso la risoluzione dei problemi (non era difficile da individuare una volta che sapevamo che era lì).

Successivamente, abbiamo inserito un database e ci siamo resi conto che il bug non avrebbe mai superato quel test di junit se stessimo andando in un database in memoria.

Nei database di memoria hanno i vantaggi:

  • possono essere convertiti rapidamente (senza bisogno di un DBA per configurare account, tabelle e simili) per il test
  • i dati possono essere preconfigurati per quel test
  • il test non ha bisogno di preoccuparsi di ripristinare il test una volta terminato
  • ogni test ha il suo database di memoria in modo da non doversi preoccupare se due test sono eseguiti contemporaneamente
  • possono essere eseguiti su sistemi che non hanno connettività con i veri database
risposta data 09.10.2013 - 18:02
fonte
1

Questo dipende molto dal sistema di database che stai utilizzando. Quando il tuo sistema db ti fornisce un'alternativa in memoria che è quasi al 100% di API e comportamento compatibile con una configurazione del database basata su disco (tranne che per velocità e sicurezza, o corso), quindi utilizzando il la variante in memoria è ovviamente valida.

Se, tuttavia, il sistema DB presenta differenze significative tra la configurazione in memoria e l'utilizzo non in memoria, hai ragione: in questo caso i test di integrazione hanno un rischio maggiore di ombreggiamento di un bug. Ma anche in questo caso, potresti essere in grado di "astrarre tali differenze" da solo, dato che conosci bene il tuo sistema DB e le differenze.

    
risposta data 09.10.2013 - 22:22
fonte
1

In parole semplici:

Il deridere le parti importanti dell'architettura è OK (e assolutamente necessario) per test delle unità .

Ma per i test di integrazione, sono assolutamente d'accordo con te. Non si dovrebbe fare il mocking e un ambiente il più simile possibile a quello che dovrebbe essere fornito.

Dopotutto, i test di integrazione riguardano il test di come le diverse parti dell'architettura si comportano insieme.

    
risposta data 09.10.2013 - 23:08
fonte

Leggi altre domande sui tag