Il problema con l'utilizzo di un database 'reale' per il test delle unità è l'impostazione, l'eliminazione e l'isolamento dei test. Non si vuole dover creare un database MySQL completamente nuovo e creare tabelle e dati solo per un test di unità. I problemi con questo hanno a che fare con la natura esterna del database e il database di test è inattivo, i test dell'unità falliscono. Ci sono anche problemi nell'assicurarsi di avere un database univoco con cui testare. Possono essere superati, ma c'è una risposta più semplice.
Il derisione del database è un'opzione tuttavia non verifica le query effettivamente eseguite. Può essere utilizzato come soluzione molto più semplice quando si desidera assicurarsi che i dati provenienti dal DAO attraversino correttamente il sistema. Ma per testare il DAO stesso è necessario qualcosa dietro al DAO che i dati e le query funzionino correttamente.
La prima cosa da fare è usare un database in memoria. HyperSQL è una scelta eccellente per questo perché ha la capacità di emulare il dialetto di un altro database - in modo che le differenze minori tra i database rimangano le stesse (dati tipi, funzioni e simili). hsqldb ha anche alcune caratteristiche interessanti per il test delle unità.
db.url=jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;
Carica lo stato del database (le tabelle, i dati iniziali) dal file testData
. shutdown=true
spegne automaticamente il database quando si chiude l'ultima connessione.
Usando iniezione di dipendenza , i test dell'unità selezionano un diverso database di quello che la produzione (o test, o locale) usa.
Il DAO utilizza quindi il database iniettato per il quale è possibile avviare test sul database.
I test unitari avranno quindi un aspetto simile (un mucchio di cose noiose non incluse per brevità):
@Before
public void setUpDB() {
DBConnection connection = new DBConnection();
try {
conn = connection.getDBConnection();
insert = conn.prepareStatement("INSERT INTO data (txt, ts, active) VALUES (?, ?, ?)");
} catch (SQLException e) {
e.printStackTrace();
fail("Error instantiating database table: " + e.getMessage());
}
}
@After
public void tearDown() {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private void addData(String txt, Timestamp ts, boolean active) throws Exception {
insert.setString(1, txt);
insert.setTimestamp(2, ts);
insert.setBoolean(3, active);
insert.execute();
}
@Test
public void testGetData() throws Exception {
// load data
Calendar time = Calendar.getInstance();
long now = time.getTimeInMillis();
long then1h = now - (60 * 60 * 1000); // one hour ago
long then2m = now - (60 * 1000 * 2); // two minutes ago
addData("active_foo", new Timestamp(then1h), true); // active but old
addData("inactive_bar", new Timestamp(then1h), false); // inactive and old
addData("active_quz", new Timestamp(then2m), true); // active and new
addData("inactive_baz", new Timestamp(then2m), false); // inactive and new
DataAccess dao = new DataAccess();
int count = 0;
for (Data data : dao.getData()) {
count++;
assertTrue(data.getTxt().startsWith("active"));
}
assertEquals("got back " + count + " rows instead of 1", count, 1);
}
E quindi, hai un test unitario che chiama il DAO e sta utilizzando i dati che sono stati impostati in un database al volo che esiste per la durata del test. Non devi preoccuparti delle risorse esterne o dello stato del database prima dell'esecuzione, o del ripristino di uno stato conosciuto (beh, lo 'stato conosciuto' è 'non esiste' che è banale da ripristinare).
DBUnit può rendere molto di ciò che ho descritto un processo più semplice nella configurazione del database, nella creazione delle tabelle e nel caricamento dei dati. Se avessi bisogno di utilizzare il database attuale per qualche ragione, questo è di gran lunga lo strumento migliore da usare.
Il codice sopra è parte di un progetto maven che ho scritto per la prova del concetto TestingWithHsqldb su github