L'unità HSQLDB verifica un pattern anti?

8

HSQLDB è fantastico. Ha anche una modalità incorporata (non è necessario alcun server dedicato), che consente la prototipazione rapida di elementi come Proof of Concepts, e può anche essere ottima nelle applicazioni pronte per la produzione, come una memorizzazione rapida e semplice di vari dati.

Tuttavia, almeno il 90% dei progetti su cui ho lavorato negli anni passati, se hanno in qualche modo a che fare con un database SQL, avranno inevitabilmente test unitari che utilizzano un HSQLDB incorporato.

Certo, questi progetti (che usano la struttura standard di Maven il più delle volte), hanno una tonnellata di "unit test" (o, almeno, qualche tipo di test, ma che si trovano nella test "area del progetto (come" src / test / java ")) che usa una o più istanze incorporate di HSQLDB per fare alcune operazioni CRUD e controllare i risultati.

La mia domanda è: è un anti-pattern? Il fatto che HSQLDB sia facile da integrare e il server embedded sia molto leggero fa sì che possa essere trascurato come "mock-up" di un vero database, quando non dovrebbe essere il caso? Questi test non dovrebbero essere trattati più come test di integrazione (dato che ognuno di essi è composto da "qualcosa" E che l'integrazione di "qualcosa" con un server di database)? Oppure mi manca qualcosa nella definizione di "unit test", e possiamo dire che usando HSQLDB in questo modo si aderisce semplicemente alla "simulazione delle dipendenze e test solo l'unità" della definizione di "unit test"?

    
posta Shivan Dragon 11.02.2014 - 12:38
fonte

6 risposte

7

Considero di utilizzare qualcosa come HSQLDB (o DBUnit) quando collaudo i miei DAO come passaggio necessario per garantire la qualità rispetto al codice che scrivo quando tocchi un livello dati. Come già sottolineato, non è una soluzione a prova di proiettile, ma in combinazione con i suoi dialetti può coprire una parte ragionevole dei tuoi casi.

Il mio unico punto sarebbe: facciamo attenzione quando parliamo di test unit . Quando provo una classe che interagisce con un componente esterno che è una specie di fuori dal mio controllo (cioè può produrre un comportamento non deterministico) lo considero automaticamente come un test di integrazione.

Supponendo di aver preso in considerazione la logica in cui interagisci direttamente con il tuo datastore (tramite driver JDBC, ORM, ecc.) in una classe concreta nascosta da un'interfaccia, un vero test unitario per il tuo DAO sarebbe sviluppato da passando ad essa un'implementazione fittizia e concreta dell'interfaccia che restituisce un insieme di valori ben noti rispetto ai quali lo testerete.

    
risposta data 17.02.2014 - 18:04
fonte
5

IMO:

  • Se un test richiede DB, non è il test dell'unità. È un test di integrazione o di accettazione.
  • Per evitare la necessità di utilizzare DB in un test, dovrei seguire il principio inversione del controllo utilizzando dipendenza per iniezione (o localizzatore di servizi).
  • Se ho bisogno di testare qualcosa con DB, dovrei creare una VM con un vero database (con dati falsi o reali, a seconda dell'attività). Vagrant e Docker sono ottimi strumenti per lavoro.
  • Prendere in giro il DB è una cattiva pratica. È lo stesso che farlo male (DB beffardo) e poi ripristinarlo correttamente (facendolo funzionare con DB reale).
  • Va bene per progetti di proof-of-concept, ma è comunque seguito da ripetizioni (se il concetto è provato).
  • È perfettamente utile usare HSQLDB (o qualsiasi altra cosa) da solo se è uno strumento adeguato per il lavoro.
risposta data 17.02.2014 - 19:20
fonte
4

Utilizza lo stesso database per i test (unità) che stai utilizzando nell'ambiente di produzione.

Il motivo è semplice: i database si comportano diversamente. Ogni database ha le proprie funzioni proprietarie. Anche se utilizzi un livello ORM per l'accesso al database, il tuo database può comportarsi diversamente, anche in termini di prestazioni.

Naturalmente, il vantaggio di un database incorporato per i test di unità è che non devi configurare nulla. Ma installare un database su ogni macchina per sviluppatori e configurarlo per i test di unità non è così difficile.

Ho avuto la stessa situazione in un progetto qualche tempo fa. Abbiamo usato JDBC per eseguire istruzioni SQL sul database. Quando abbiamo deciso di scrivere test per la nostra applicazione, abbiamo utilizzato un database incorporato. Ciò ha portato a situazioni in cui alcuni bug non potevano essere riprodotti con test unitari e alcune parti dell'applicazione non potevano essere testate perché il database incorporato non supportava le funzioni del nostro database di produzione. Così ogni sviluppatore ha installato lo stesso database che abbiamo utilizzato anche nell'ambiente di produzione sul PC per eseguire i test, che ha funzionato molto meglio.

    
risposta data 11.02.2014 - 13:14
fonte
3

Ho trovato & risolto alcuni problemi veramente brutti e notevolmente accelerato il mio sviluppo testando il database HSQL. Spesso il livello più basso di classi di adattatori (ad esempio i tuoi DAO) non può essere verificato durante il test delle unità poiché può essere difficile separarli da un vero e proprio viaggio di andata e ritorno in un database attivo. In passato ho simulato le risorse di Connection e JDBC, ma in realtà era molto più difficile rispetto a un database in memoria.

In un progetto, ho sviluppato e amp; testato contro HSQL, eseguito localmente contro MySql e distribuito in produzione contro SQL Server. Sorprendentemente, ha funzionato bene. Il più grande problema di integrazione che ho riscontrato è dovuto al mio fraintendimento delle specifiche (secondi contro millisecondi, lol).

Mentre il framework di persistenza può mascherare il database sottostante (come fa Hibernate), lo stesso framework di persistenza può aggiungere semantica abbastanza complicata che esercitarsi in isolamento può liberare un sacco di stranezze prima di arrivare a test di integrazione in piena regola.

Considera il caso in cui stai utilizzando Hibernate o JPA per creare un set di risultati complicato con molti join. Se è brutto e richiede un sacco di tentativi, è possibile svilupparlo e testarlo su un database live. Ma potresti anche svilupparlo e testarlo su un database in memoria con meno overhead. Inoltre, non devi preoccuparti degli script di installazione / cancellazione per i tuoi dispositivi di database, o del coordinamento di test e build con altri. E se si prova contro il database in memoria, si godono i vantaggi di avere quei test in giro per la regressione, proprio come gli altri test unitari.

Ho sentito il termine "Component Testing" per test che sono più di un test unitario, ma che sono ancora eseguiti in isolamento.

Test unitari, test dei componenti (se questo è davvero il loro nome) e Test di integrazione forniscono tutti valore. Le squadre possono fare a meno dell'uno o dell'altro (sì, molti team non fanno test unitari e si affidano esclusivamente ai test di integrazione), ma se lo fai, stai perdendo i benefici che gli altri livelli di test portano.

Nel caso di test isolati in virtù dell'integrazione in memoria, il vantaggio è una rapida convalida del codice e quindi una rapida regressione: i vantaggi dei test isolati e la necessità di installazioni, licenze o hardware aggiuntivi. Ti consente di convalidare più livelli di codice in isolamento rispetto a quando ti sei limitato a testare i tuoi DAO fino al provisioning del database.

Quindi c'è un valore pratico. Non è richiesto, ma sono stato più felice che meno quando l'ho fatto.

    
risposta data 22.02.2014 - 03:18
fonte
2

Uso approcci come questo in passato, non sono sicuro che si tratti di un "anti-pattern" (alcune persone cercano di elevare i suoi sentimenti personali o le esperienze a regole universali, non lo sono), ma preferisco un altro approccio:

  • Per il test unitario, il test dell'unità reale non utilizza elementi esterni come un database in memoria (non molto leggero se si confronta con un hashMap o uno stub utilizzando una libreria stub). Se si utilizza DI e modelli semplici come Repository o DAO per l'accesso ai dati, è molto facile da ottenere. Il mio obiettivo è di avere un sacco di test unitari che si eseguano molto velocemente, e con rapidità sto pensando in 3k test in meno di un minuto.

  • Per il test di integrazione, preferisco utilizzare il software di archiviazione dati reale in questo test, l'obiettivo di questo test è dimostrare l'integrazione tra il mio software e l'archiviazione dei dati reale, utilizzare una diversa memorizzazione dei dati qui rompe l'intenzione di questo test. Provo a scrivere il test di integrazione il più possibile per dimostrare questa integrazione, e solitamente questo test viene eseguito al di fuori della build normale (ad esempio solo nelle build notturne)

A volte uso HSQLDB per creare semplici dimostrazioni o dimostrazioni di concetti, è un ottimo strumento, ma non vedo più quale sia il suo ruolo in questo strumento nel mio normale flusso di lavoro di sviluppo.

    
risposta data 17.02.2014 - 20:39
fonte
0

Per i dati sui test delle unità di accesso a prodotti come MyBatis, i test che utilizzano HSQLDB incorporato sono perfettamente a mio avviso (e so che MyBatis sta utilizzando HSQLDB esattamente per questo).

Per la maggior parte degli altri progetti considererei questo overkill. Vorrei fare alcuni semplici test di integrazione (questi sono test che potenzialmente hanno effetti collaterali su altri test) che accedono al database reale, assicurando che ogni query / istruzione sia utilizzata almeno una volta. Ci dovrebbero essere molti meno test di integrazione rispetto ai test unitari nel progetto.

Per i test delle unità, prenderei in giro il DAO o qualunque cosa acceda al DB (l''adattatore').

    
risposta data 17.02.2014 - 19:35
fonte

Leggi altre domande sui tag