Il problema con l'utilizzo di un database "reale" per i test unitari è l'installazione, il decollo e l'isolamento dei test. Non è necessario creare un database MySQL completamente nuovo e creare tabelle e dati solo per un test unitario. I problemi con questo hanno a che fare con la natura esterna del database e il database di test è inattivo, i test delle unità falliscono. Ci sono anche problemi nell'assicurarsi di disporre di un database univoco per il test. Possono essere superati, ma c'è una risposta più semplice.
Deridere il database è un'opzione, tuttavia non verifica le query effettive che vengono eseguite. Può essere utilizzato come soluzione molto più semplice quando si desidera assicurarsi che i dati del DAO attraversino correttamente il sistema. Ma per testare il DAO stesso è necessario qualcosa dietro al DAO che i dati e le query vengono eseguite correttamente.
La prima cosa da fare è utilizzare 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 (tipi di dati, funzioni e simili). hsqldb ha anche alcune belle funzioni per i test unitari.
db.url=jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;
Questo carica lo stato del database (le tabelle, i dati iniziali) dal testData
file. shutdown=true
chiuderà automaticamente il database alla chiusura dell'ultima connessione.
Utilizzando l' iniezione delle dipendenze , fare in modo che i test unitari selezionino un database diverso da quello utilizzato dalla produzione (o test o locale).
Il DAO utilizza quindi il database iniettato per il quale è possibile avviare i test sul database.
I test unitari appariranno quindi simili (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 unit test che chiama il DAO e sta usando 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 a uno stato noto (beh, lo "stato noto" è "non esiste", che è banale a cui tornare).
DBUnit può fare molto di quello che ho descritto un processo più semplice nell'impostazione del database, nella creazione delle tabelle e nel caricamento dei dati. Se avessi bisogno di utilizzare il database reale per qualche motivo, 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