Montag, 10. November 2014
Einführung in JUnit

Einführung in JUnit

Eine wesentliche Änderung gegenüber JUnit 3 ist, dass es keine speziellen Testklassen mehr geben muss. Die Testmethoden, welche die Tests durchführen, können einen beliebigen Namen haben und in einer beliebigen Klasse stehen. Der Übersichtlichkeit halber finde ich jedoch, dass die Tests in eine eigene Klasse gehören, was ich in meinen Beispielen auch so durchführe. Diese Klasse trägt das Suffix Test und die Testmethoden beginnen mit teste, anschließend folgt der Name der zu testenden Methode.

Getestet werden soll eine einfache Konto-Klasse namens Konto. Die Klasse enthält ein Attribut für den Betrag auf dem Konto und jeweils eine Methode zum Abbuchen und zum Einzahlen. Dabei müssen natürlich bestimmte Fälle geprüft werden. So darf bspw. der Kontostand durch Abbuchen nicht unter 0 fallen.

Die Kontoklasse

Zuerst entwerfen wir einen einfachen Prototyp für unsere Kontoklasse. Wir definieren wie im ersten Teil des Tutorials beschrieben die notwendigen Attribute und die Methoden, die getestet werden sollen. Außerdem benötigten wir einen Konstruktor, der alle verpflichtenden Daten entgegen nimmt. Im Folgenden sehen Sie eine einfache minimale Kontoklasse. Der Übersichtlichkeit halber wird auf Getter und Setter verzichtet. Nach dem Prinzip Test First enthält der Prototyp noch keine Funktionalität.

public class Konto { 
	private String inhaber; 
	private String kontonr; 
	private float betrag; 
	public Konto(String inhaber, String kontonr, 
				 float betrag) { } 
	public void einzahlen(float betrag) { } 
	public void auszahlen(float betrag) { } 
}

Unser erster Test

import org.junit.Test; 
import static org.junit.Assert.*; 
public class KontoTest { 
	@Test public void testeEinzahlen() { 
		Konto konto = new Konto("Schmitt", "12345", 500); 
		konto.einzahlen(500); 
		AssertEquals(konto.getBetrag(), 1000.0, 0.001); 
	} 
	
	@Test public void testeAuszahlen() { 
		Konto konto = new Konto("Schmitt", "12345", 500); 
		konto.auszahlen(300); 
		AssertEquals(konto.getBetrag(), 200.0, 0.001); 
	} 
}

Nehmen wir einmal die oben gezeigt Testklasse KontoTest auseinander. Zuerst einmal sehen Sie zwei Imports. Der statische Import importiert die statischen Methoden einer anderen Klasse. Mit der Anweisung in unserer Klasse holen wir uns einfach alle statischen Methoden auf einmal. Somit müssen wir den Aufruf der Methode nicht so schreiben: Assert.AssertEquals()

Die Methoden, die als Testfälle ausgeführt werden sollen, werden mit der Annotation @Test markiert. Die Methoden können einen beliebigen Namen haben, allerdings sollten sie wegen guter Konvention mit dem Präfix test oder teste beginnen. Die Testmethoden müssen parameterlos sein und dürfen keinen Rückgabewert haben.

In der Testmethode selbst legen wir ein neues Konto mit einem Startguthaben von 500 Euro an. Dann zahlen wir weitere 500 Euro ein. Interessant ist die Methode AssertEquals. Sie überprüft, ob zwei Werte gleich sind. Da Gleitkommazahlen niemals vollkommen identisch sind, kann ein Toleranzwert als dritter Parameter angegeben werden. Unsere Anweisung überprüft also, ob der im Konto gespeicherte Betrag gleich 1000 ist, wovon wir bei unserem Test ausgehen sollten. Ist dies nicht der Fall, ist der Test schief gelaufen und in unserer Methode einzahlen() ist wahrscheinlich ein Fehler - möglicherweise aber auch schon im Konstruktor.

Ähnlich läuft die zweite Testmethode an. Wir markieren sie mit @Test, legen ein neues Konto an, führen die Methode auszahlen() aus und prüfen, ob das Konto den erwarteten Betrag von 200 Euro hat.

Die Klasse Assert

Die Klasse Assert enthält statische Methoden, mit denen es möglich ist, Werte und Bedingungen zu testen. Diese Bedingungen müssen erfüllt sein, damit der Test korrekt läuft. Ist dies nicht der Fall wird ein AssertionError ausgelöst. Für uns das Signal, dass während des Tests ein Fehler aufgetreten ist, der korrigiert werden möchte.

In der Klasse Assert sind eine ganze Reihe solcher assert-Methoden definiert, die ich im Folgenden kurz vorstellen möchte.

assertTrue() und assertFalse()

assertTrue(boolean condition) überprüft, ob eine Bedingung wahr ist, assertFalse(boolean condition) überprüft, wie der Name schon sagt, ob eine Bedingung falsch ist. In unserem Konto könnte es eine Methode sperren() geben und einen Getter istGesperrt(). Rückgabe wäre vom Typ boolean und somit durch assertTrue() oder assertFalse() auswertbar:

assertTrue(konto.istGesperrt());

assertArrayEquals

Diese Methoden führen Vergleiche von Feldinhalten durch. Die Syntax lautet entsprechend der assertEquals-Methoden: assertArrayEquals(Object[] expected, Object[] actual)

assertEquals()

Die verschiedenen assertEquals-Methoden prüfen auf Gleichheit zweier Werte. Damit können primitive Datentypen (int, double usw.) auf Gleichheit geprüft werden. Bei zwei Objekten wird ein korrekter equals()-Vergleich und kein Referenzenvergleich durchgeführt. Die Syntax dieser Methoden sieht also allgemein so aus: assertEquals(Object expected, Object actual). Nur bei Gleitkommazahlen muss wie bereits erwähnt noch ein Toleranzwert angegeben werden, da bei der Gleitkommarithmetik zwei Werte im Allgemeinen nicht ganz gleich sind.

assertNull(), assertNotNull() und assertSame()

Diese drei Methoden führen Referenzenvergleiche durch. Die ersten beiden prüfen, ob eine Referenz null ist oder nicht. assertSame(Object expected, Object actual) prüft, ob zwei Referenzen gleich sind. Es wird also kein equals()-Test durchgeführt.

Zu allen hier vorgestellten Methoden gibt es noch eine Variante, bei der als erster Parameter eine Fehlermeldung als String mitgegeben werden kann.

Was passiert, wenn ein Test fehlschlägt?

Der laufende Test wird im Fehlerfall abgebrochen. Im Fehlerfall bedeutet, dass die assert-Methoden die Behauptungen nicht verifizieren konnten. Es wird eine Ausnahme vom Typ AssertionError geworfen. Die Fehler werden in einem speziellen Object, dem Result, gespeichert. Dieses wird einem Runner übergeben, der normalerweise in der IDE integriert ist. Der Runner gibt die Testergebnisse für uns aus.

Daher können Unit-Tests im Allgemeinen sehr einfach durch die IDE ausgeführt werden. BlueJ, Eclipse, Netbeans usw. bieten alle entsprechende Komponenten, um Unit-Tests mit JUnit durchführen und die Ergebnisse bewundern zu können.

... comment