Das Problem bei der Verwendung einer "echten" Datenbank für Komponententests ist das Einrichten, Herunterfahren und Isolieren der Tests. Sie möchten keine völlig neue MySQL-Datenbank hochfahren und Tabellen und Daten nur für einen Komponententest erstellen müssen. Die Probleme damit haben mit der externen Natur der Datenbank zu tun und Ihre Testdatenbank ist ausgefallen, Ihre Komponententests schlagen fehl. Es gibt auch Probleme damit, sicherzustellen, dass Sie eine eindeutige Datenbank zum Testen haben. Sie können überwunden werden, aber es gibt eine einfachere Antwort.
Das Verspotten der Datenbank ist eine Option, testet jedoch nicht die tatsächlich ausgeführten Abfragen. Es kann als viel einfachere Lösung verwendet werden, wenn Sie sicherstellen möchten, dass die Daten vom DAO das System ordnungsgemäß durchlaufen. Aber zum Testen des DAO selbst brauchst du etwas, hinter dem DAO die Daten hat und die Abfragen einwandfrei laufen.
Als Erstes müssen Sie eine In-Memory-Datenbank verwenden. HyperSQL ist hierfür eine ausgezeichnete Wahl, da es den Dialekt einer anderen Datenbank emulieren kann - so dass die geringfügigen Unterschiede zwischen Datenbanken gleich bleiben (Datentypen, Funktionen und dergleichen). Hsqldb hat auch einige nette Funktionen für Unit-Tests.
db.url=jdbc:hsqldb:file:src/test/resources/testData;shutdown=true;
Dadurch wird der Status der Datenbank (Tabellen, Anfangsdaten) aus der testData
Datei geladen. shutdown=true
wird die Datenbank automatisch herunterfahren, wenn die letzte Verbindung geschlossen wird.
Lassen Sie die Komponententests mithilfe der Abhängigkeitsinjektion eine andere Datenbank auswählen, als sie von der Produktions- (oder Test- oder lokalen) Builds verwendet wird.
Ihr DAO verwendet dann die injizierte Datenbank, für die Sie Tests für die Datenbank starten können.
Die Unit-Tests sehen dann so aus (ein paar langweilige Sachen, die der Kürze halber nicht enthalten sind):
@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);
}
Sie haben also einen Komponententest, der das DAO aufruft und die Daten verwendet, die für die Dauer des Tests in einer On-the-Fly-Datenbank eingerichtet wurden. Sie müssen sich keine Gedanken über externe Ressourcen oder den Status der Datenbank machen, bevor Sie sie ausführen oder einen bekannten Status wiederherstellen (der bekannte Status ist "nicht vorhanden" und es ist trivial, ihn wiederherzustellen).
DBUnit kann vieles von dem, was ich beschrieben habe, vereinfachen, indem es die Datenbank einrichtet, die Tabellen erstellt und die Daten lädt. Wenn Sie aus irgendeinem Grund die eigentliche Datenbank benötigen, ist dies bei weitem das bessere Werkzeug.
Der obige Code ist Teil eines Maven-Projekts, das ich für den Proof-of-Concept- Test mit Hsqldb auf Github geschrieben habe