JUnit - Optimierung der Testklassen

PHANTOMIAS

Aktives Mitglied
Hallo an alle!

Ich habe einige JUnit-Testklassen und drei statische Methoden darin sind immer gleich. Nun wäre es wohl angebracht diese Redundanz zu entfernen, aber wie macht man das am Besten?

Das sind die Methoden:
Java:
// Diese Methode soll in der Testklasse bestehen bleiben, hier werden unterschiedliche Dinge getan
@BeforeClass
public static void init() throws Exception {
	...
	// Aufruf der Methode in der Testklasse
	doSetup();
}

private static void doSetup() throws Exception {
	final IDatabaseConnection conn = getConnection();
	final IDataSet data = getDataSet();
	try {
		DatabaseOperation.CLEAN_INSERT.execute(conn, data);
	} finally {connection.close();}
}

private static IDataSet getDataSet() throws IOException, DataSetException {
	return new FlatXmlDataSetBuilder().build(new FileInputStream("database.xml"));
}

private static IDatabaseConnection getConnection() throws ClassNotFoundException, SQLException {
	Class.forName("com.mysql.jdbc.Driver");
	try {
		return new DatabaseConnection(DriverManager.getConnection("jdbc:mysql://localhost/testdb", "root", "passwort"));
	} catch (DatabaseUnitException e) {e.printStackTrace();}
	return null;
}
Wie kann ich diese auslagern? Wenn ich vererbe mit einer Oberklasse Test, so findet der Aufruf doSetup() nicht die Methode in der Oberklasse.

Jemand eine Idee?

Danke & Gruss PHANTOMIAS
 
Eine Utility Klasse welche die 3 statischen Methoden enthält wäre eine Möglichkeit.

Nebenbei, wenn du die DB nur im @BeforeClass initalisierst, solltest du nur lesende Tests machen, sonst ändern sich die Daten von Test zu Test, und letztere sollten immer unabhängig voneinander sein.

Ansonsten kannst du ja noch den Weg einschlagen vor jedem Testcase die DB zu initialisieren, dann brauchst du diese Methoden auch nicht mehr statisch, solltest dann aber unbedingt einen ConnectionPool verwenden, oder du initalisierst eben in deinr @BeforeClass Methode die DB, aber erzeugst dafür ein Objekt.
static ist einschränkend wenn es um Vererbung geht.
 
mich verwirrt die Datenbank connection in einem Unit test ?
willst du nicht eher ein integrationsttest machen ?

wenn deine Funktionalität irgendwas aus einer DB braucht um zu funktionieren schau dir mal lieber Mocks/Spys etc an.

eine offene DB in einem unittest ist mehr als verdächtig...
 
Ich kann für DB-Tests HSQL empfehlen, das geht noch ein Zacken schneller und Du brauchst keinen Datenbankserver aufzusetzen oder zu benutzen.

edit: ansonsten Mocken, aber irgendwann möcht man ja mal die DB-Funktionalität testen.
 
Wo wird denn die Korrektheit der Datenbankzugriffe sonst getestest? Ich verwende dazu DBUnit und HSQL (setzt natürlich voraus, das der Datenbanklayer mehr als nur einen DB-Dialekt unterstützt.
 
bygones hat schon recht, das ist kein Unittest mehr, sondern ein Integrationstest, dafür auch DBUnit.

Ansonsten bleibt das gesagte aber gültig, irgendwie muss man ja die DB testen, und da dieser Test eben die DB braucht, ist es ein Integrationstest.
 
Vielen Dank für eure vielen Antworten. Ich werde mal darauf eingehen:

Eine Utility Klasse welche die 3 statischen Methoden enthält wäre eine Möglichkeit.
Habe ich so nun gemacht, funktioniert einwandfrei, danke!

Nebenbei, wenn du die DB nur im @BeforeClass initalisierst, solltest du nur lesende Tests machen, sonst ändern sich die Daten von Test zu Test, und letztere sollten immer unabhängig voneinander sein.
Man erkennt mich als Laien wohl schneller als erwartet 🙂 Ich habe vor ein paar Monaten schon mal damit begonnen mich mit dem Testen auseinanderzusetzen, dann eine Pause eingelegt, und nun geht es weiter. Und ja, ich setze einmal pro Testklasse die Datenbank neu auf. Ist es besser das vor jeder Funktionalität (Methode) zu machen? Falls ja, wie geht das? ConnectionPool sagt mir in diesem Zusammenhang (noch) nichts.

Ich nutze JUnit / DbUnit zum Testen meiner Services.
Ich dachte mit einem Unit-Test, testet man eine Einheit? Und der Test eines Service ist für mich eigentlich eine Einheit mit der Datenbank zusammen?

Ist das nur eine Begrifflichkeit oder sollte man nicht JUnit dafür verwenden?
 
Ich dachte mit einem Unit-Test, testet man eine Einheit?
Eben.

Und der Test eines Service ist für mich eigentlich eine Einheit mit der Datenbank zusammen?
Eben nicht.

"Mit der Datenbank zusammen" oder "mit dem Dateisystem" etc. sind sog. Integrationstests, weil abhängigkeiten über Systemgrenzen hinaus benötigt werden.
Ein isolierter Unittest würde, wie schon bereits erwähnt wurde, Mockobjekte oder Stubs nutzen.

Man kann JUnit auch dafür verwenden, kein Problem.
Integrationstests sind meist langsamer und komplexer.

Ist es besser das vor jeder Funktionalität (Methode) zu machen?
Was heisst "besser", entweder richtig oder nicht.
Wenn eine deiner Testcases in die DB schreibt (INSERT, UPDATE, DELETE) und dann deren Werte ändert, beeinflusst das einen anderen deiner Testcases?
Was ist, wenn ein Testcase fehlschlägt, beeinflusst dass einen anderen Testcase?

Falls ja, wie geht das?
@Before kennst du?

ConnectionPool sagt mir in diesem Zusammenhang (noch) nichts.
Dann wird es aber Zeit, gehört zum JDBC Standard.
Musst aber erst feststellen ob dir die Tests ohne nicht doch schnell genug sind.
 
"Mit der Datenbank zusammen" oder "mit dem Dateisystem" etc. sind sog. Integrationstests, weil abhängigkeiten über Systemgrenzen hinaus benötigt werden.
Ein isolierter Unittest würde, wie schon bereits erwähnt wurde, Mockobjekte oder Stubs nutzen.

Man kann JUnit auch dafür verwenden, kein Problem.
Integrationstests sind meist langsamer und komplexer.

recht haste!
 
Da hast du vollkommen recht mit: Schlägt einer fehl, so hat das Konsequenzen für die nachfolgenden Testmethoden und das sehe ich ein, das ist ganz und gar nicht gut.

Ich habe nun das doSetup() aus der @BeforeClass herausgenommen und eine neue Methode folgendermaßen eingebunden:

Java:
@Before
public void setupBeforeMethod() throws Exception {
    MyTestUtil.doSetup();
}

Nun wird vor jeder Test-Methode die Datenbank neu eingespielt.

Okay, ConnectionPool bedeutet, dass Datenbankverbindungen aktiv bleiben und aus einem Pool eine offene genommen werden kann. Das steigert dann die Geschwindigkeit. Also für meine Mini-Anwendung mit gerade mal 6 Datenbanktabellen ist es ausreichend. Habe eventuell nur daran gedacht eine HSQLDB zu nehmen, aber die Geschwindigkeit ist i.O., die Tests dauern insgesamt weniger als 5 Sekunden.

Gruß PAHNTOMIAS
 
Die Tests sollen untereinander unabhängig sein und sich auch nicht gegenseitig beeinflussen können (jeder Test soll einen definierten Startzustand haben).
HSQL ist wirklich sehr easy zu benutzen, einfach die JAR einbinden, die Connection holen und schon läuft der HSQL-Server. Ich habe mal in einer Firma gearbeitet, da sind die Integrationstest um die halbe Stunde lang gelaufen. Nachdem Einbau von HSQL konnte man die Integrationstests minütlich zünden 🙂
 
Jo, aber ob 10 oder 2 ist bei 10 Tests schon ein Unterschied.

Ich nutze Hibernate und H2 auch als Memory-DB in Tests und man merkt schon den Unterschied zwischen File-Db oder Mem-DB.
 

Zurück
Oben