2010-09-24 17 views
31

Ho un'applicazione in cui molti "unità" test utilizzano una connessione reale a un database Oracle durante la loro esecuzione.Creare una struttura di database in memoria da un'istanza Oracle

Come potete immaginare, questi test impiegano troppo tempo per essere eseguiti, poiché devono inizializzare alcuni contesti Spring e comunicare con l'istanza Oracle. Oltre a questo, dobbiamo gestire meccanismi complessi, come le transazioni, al fine di evitare modifiche al database dopo l'esecuzione del test (anche se usiamo classi utili da Spring come AbstractAnnotationAwareTransactionalTests).

Quindi la mia idea è di sostituire progressivamente questa istanza di test Oracle da un database in memoria. Userò hsqldb o forse meglio h2.

La mia domanda è sapere qual è l'approccio migliore per farlo. La mia preoccupazione principale è legata alla costruzione della struttura del database in memoria e all'inserimento dei dati di riferimento.

Naturalmente, posso estrarre la struttura del database da Oracle, utilizzando alcuni strumenti come SQL Developer o TOAD, e quindi modificare questi script per adattarli alla lingua hsqldb o h2. Ma non penso che sia l'approccio migliore.


In realtà, ho già fatto su un altro progetto che utilizza hsqldb, ma mi hanno scritto manualmente tutti gli script per creare le tabelle. Fortunatamente, avevo solo poche tabelle da creare. Il mio problema principale durante questo passaggio è stato quello di "tradurre" gli script Oracle utilizzati per creare tabelle nella lingua hsqldb.

Ad esempio, una tabella creata in Oracle utilizzando il seguente comando SQL:

CREATE TABLE FOOBAR (
    SOME_ID NUMBER, 
    SOME_DATE DATE, -- Add primary key constraint 
    SOME_STATUS NUMBER, 
    SOME_FLAG NUMBER(1) DEFAULT 0 NOT NULL); 

aveva bisogno di essere "tradotto" per hsqldb a:

CREATE TABLE FOOBAR (
    SOME_ID NUMERIC, 
    SOME_DATE TIMESTAMP PRIMARY KEY, 
    SOME_STATUS NUMERIC, 
    SOME_FLAG INTEGER DEFAULT 0 NOT NULL); 

Nel mio progetto attuale, ci sono anche molte tabelle per farlo manualmente ...


Quindi le mie domande:

  • Quali sono i consigli che puoi darmi per raggiungere questo obiettivo?
  • h2 o hsqldb forniscono alcuni strumenti per generare i propri script da una connessione Oracle?

informazioni tecniche

Java 1.6, Primavera 2.5, Oracle 10.g, Maven 2


Modifica

Alcune informazioni riguardanti mio test di unità:

Nell'applicazione in cui ho usato hsqldb, ho avuto le seguenti prove: - Alcune unità di "base" test, che non hanno nulla a che fare con DB. - Per il test DAO, ho usato hsqldb per eseguire manipolazioni del database, come CRUD. - Poi, sul livello di servizio, ho usato Mockito per deridere i miei oggetti DAO, al fine di concentrarmi sul test di servizio e non sulle intere applicazioni (cioè servizio + dao + DB).

Nella mia attuale applicazione, abbiamo lo scenario peggiore: i test di livello DAO richiedono l'esecuzione di una connessione Oracle. Il livello di servizi fa non usa (ancora) qualsiasi oggetto fittizio per simulare il DAO. Quindi i test di servizio anche richiedono una connessione Oracle.

Sono consapevole del fatto che i mock e il database in memoria sono due punti di separazione, e li affronterò il prima possibile. Tuttavia, il mio primo passo è provare per rimuovere la connessione Oracle da un database in memoria, e quindi userò le mie conoscenze Mockito per migliorare i test.

Nota che voglio anche separare i test di unità dai test di integrazione. Quest'ultimo avrà bisogno di un accesso al database Oracle, per eseguire test "reali", ma la mia preoccupazione principale (e questo è lo scopo di questa domanda) è che quasi tutti i miei test unitari non vengono eseguiti in isolamento oggi.

risposta

19

Utilizzare un database in memoria/Java per il test. Ciò garantirà che i test siano più vicini al mondo reale rispetto a quando si tenta di "astrarre" il database nel test. Probabilmente tali test sono anche più facili da scrivere e mantenere. D'altra parte, ciò che probabilmente vuoi "astrarre" nei tuoi test è l'interfaccia utente, perché i test dell'interfaccia utente sono solitamente difficili da automatizzare.

La sintassi Oracle che hai postato funziona bene con il database H2 (l'ho appena testato), quindi sembra che H2 supporti la sintassi Oracle meglio di HSQLDB. Disclaimer: sono uno degli autori di H2. Se qualcosa non funziona, inseriscilo nella mailing list di H2.

Si dovrebbe comunque avere le istruzioni DDL per il database nel proprio sistema di controllo versione. Puoi usare quegli script anche per i test. Probabilmente hai anche bisogno di supportare più versioni dello schema - in tal caso potresti scrivere script di aggiornamento della versione (alter table ...). Con un database Java puoi testare anche quelli.

A proposito, non è necessario utilizzare la modalità in memoria quando si utilizza H2 o HSQLDB. Entrambi i database sono veloci anche se si persistono i dati. E sono facili da installare (solo un file jar) e necessitano di molta meno memoria di Oracle.

+2

Dato che il codice DAO sembra strettamente accoppiato a Oracle e il DAO non può essere estratto, questo sembra l'approccio migliore, anche se si spera che il codice DAO non si basi su alcuna peculiarità di Oracle. Meglio sbrogliare i DAO al più presto ... –

2

Quali sono i test unitari per? Se testano il corretto funzionamento dei DDL e delle stored procedure, è necessario scrivere i test "più vicini" a Oracle: senza codice Java o senza Spring e altre belle interfacce Web a tutti concentrandosi sul db.

Se si desidera testare la logica dell'applicazione implementata in Java e Spring, è possibile utilizzare oggetti fittizi/connessione database per rendere i test indipendenti dal database.

Se si desidera testare il funzionamento nel suo complesso (cosa contraria al principio di sviluppo e test modulare), è possibile virtualizzare il database e testarlo senza rischiare di apportare alcune modifiche irreversibili.

+0

Ho modificato la mia domanda per essere più preciso sul motivo per cui voglio utilizzare un db in memoria. – romaintaz

4

L'ultimo HSQLDB 2.0.1 supporta la sintassi ORACLE per DUAL, ROWNUM, NEXTVAL e CURRVAL tramite un flag di compatibilità della sintassi, sql.syntax_ora = true. Allo stesso modo, la concatenazione di una stringa con una stringa NULL e le restrizioni su NULL nei vincoli UNIQUE vengono gestite con altri flag. La maggior parte delle funzioni di Oracle, come TO_CHAR, TO_DATE, NVL ecc sono già costruiti in

Al momento, di utilizzare dei semplici tipi ORACLE come il numero, è possibile utilizzare una definizione di tipo:.

Crea tipo NUMERO come numerico

La prossima istantanea consentirà NUMBER (N) e altri aspetti della compatibilità del tipo ORACLE quando viene impostato il flag.

Download da http://hsqldb.org/support/

[Aggiornamento:] L'istantanea emessa il 4 ott traduce maggior parte dei tipi specifici di Oracle ai tipi ANSI SQL. HSQLDB 2.0 supporta anche il tipo di INTERVAL SQL ANSI e l'aritmetica data/data/ora allo stesso modo di Oracle.

1

Fintanto che i test si puliscono da soli (come sembri già sapere come configurare), non c'è niente di sbagliato nell'esecuzione di test su un'istanza di database reale. In effetti è l'approccio che di solito preferisco, perché testerai qualcosa il più vicino possibile alla produzione.

Le incompatibilità sembrano piccole, ma in realtà finiscono per mordere non molto tempo dopo. In un buon caso, potresti farti franca con una traduzione di sql sgradevole/una grande presa in giro. In casi brutti, alcune parti del sistema saranno semplicemente impossibili da testare, il che ritengo sia un rischio inaccettabile per i sistemi business-critical.

+4

"* Non c'è niente di sbagliato nell'esecuzione di test su un DB reale *". Non sono d'accordo con quello. L'utilizzo di un DB reale per ** unit ** test non è una buona idea, per almeno 2 ragioni: 1. il test dipende dal DB e può fallire solo perché il DB è inattivo. 2. Creare una connessione a un DB reale è più costoso, e quando parli di centinaia di test, le loro esecuzioni saranno un problema. Soprattutto in un modo TDD. – romaintaz

+3

Ma ovviamente, avere test che accedono a un DB reale è anche una buona idea, ma non abbiamo a che fare con ** unit ** testing, ma più di ** integration ** test. E questo non era il mio punto qui. – romaintaz