Anwendung


... [ Seminar "JUnit" ] ... [ Inhaltsverzeichnis ] ... [ zurück ] ... [ weiter ] ...

Übersicht: Anwendung


TestCase

Die Klasse junit.framework.TestCase stellt für den Entwickler (Tester) bei der Implementierung eigener Tests die abzuleitende Klasse dar. Sie selbst implementiert das Interface Test, dessen Zusammenhang mit dieser Klasse später bei der Betrachtung der Testsuiten (TestSuite) beschrieben werden soll.

Es folgt eine vereinfachte Implementierung der Klasse TestCase:

01 public abstract class TestCase implements Test {
02   private final String fName;
03   
04   public TestCase(String name) {
05     fName = name;
06   }
07   
08   public void run() {
09     setUp();
10     runTest();
11     tearDown();
12   }
13 }
code1.java

Codebeispiel 1


Wie zu erkennen ist, wird durch den Konstruktor lediglich ein Name, zur späteren Identifikation des Testfalles durch den Entwickler, als private Variable, gespeichert. Interessanter ist jedoch die Methode run, welche die drei Methoden setUp(), runTest() und tearDown() aufruft.

Hierbei gilt: jeder Test im JUnit-Framework wird durch die drei oberen Aufrufe durchgeführt. Die Funktionen verrichten während des Tests die folgenden Aufgaben:

setUp(): Bereitet die Testumgebung darauf vor den Test durchzuführen (z.B. Initialisierung von Fixtures, Aufbau von Datenbankverbindungen etc.)

runTest(): Führt den eigentlichen Test / die eigentlichen Tests aus.

tearDown(): Kann dazu benutzt werden die mit setUp() initialisierten Werte aufzuräumen (wie z.B. Datenbankverbindungen kappen).

Die Templates der drei Methoden in der abstrakten Klasse TestCase sehen dabei wie folgt aus:

01 protected void setUp() {};
02 protected void runTest() {};
03 protected void tearDown() {};
code2.java

Codebeispiel 2


Das Verfassen eines Tests geht also durch die Erweiterung der Klasse TestCase - spezieller - durch das Überschreiben von mindestens der Methode runTest() vonstatten. Diese wird wie oben besprochen durch die Aufstellung von Behauptungen (Assert) erweitert.

Das Ausführen von Tests reicht in diesem Zusammenhang jedoch nicht vollkommen aus. Vielmehr ist auch die Fehlererkennung und Protokollierung eine der grundlegenden Anforderungen an JUnit. Diese Anforderungen werden zum Teil durch die Klasse TestResult, zum anderen durch deas TestCase selbst abgedeckt.


[ nach oben ]

Protokolierung

Da die Ausführung eines Tests dem Entwickler nicht viel über das positive bzw. negative Ergebnis des Tests auszusagen vermag, wird zur Protokollierung der aufgetretenen Fehler ein weiteres Konstrukt, das TestResult, eingeführt.

Zur Veranschaulichung erweitern wir die obere vereinfachte Definition von TestCase:

01 public abstract class TestCase implements Test {
02   // ...
03   
04   public void run(TestResult result) {
05     result.startTrue(this);
06     setUp();
07     runTest();
08     tearDown();
09   }
10 
11   public TestResult run() {
12     TestResult result = new TestResult();
13     run(result);
14     return result;
15   }
16 }
code3.java

Codebeispiel 3


Wir erkennen, dass JUnit neben der eigentlichen Methode run(), auch eine Implementierung mit Übergabe einer Instanz der Klasse TestResult bereithält. Nach außen hin wird der Entwickler mit dieser jedoch nicht in Kontakt treten müssen. Vielmehr greift die parameterlose Variante intern auf die parametrisierte Variante zurück.

Das Ergebnis eines Tests wird also in Form eines TestResult von der Methode run() an das Testframework zurückgeliefert. Betrachten wir zur weiteren Veranschaulichung eine vereinfachte Implementierung dieser Klasse:

01 public class TestResult extends Object {
02   protected int fRunTests;
03   protected Vector fFailures;
04   protected Vector fError;
05   
06   public TestResult() {
07     fRunTests = 0;
08   }
09   
10   public synchronized void startTest(Test test) {
11     fRunTests++;
12   }
13   
14   public synchronized void addError(Test test, Throwable t) {
15     fErrors.addElement(new TestFailure(test, t));
16   }
17   
18   public synchronized void addFailure(Test test, Throwable t) {
19     fFailure.addElement(new TestFailure(Test, t));
20   }
21 }
code4.java

Codebeispiel 4


Neben der Aufgabe des Zählens der durchgeführten Tests, übernimmt diese Klasse auch die Aufgabe, die aufgetretenen Fehler zu speichern. Dabei unterscheidet JUnit zwei Arten von Fehlern:
Die Klasse TestFailure dient JUnit lediglich als Hilfsklasse zur Speicherung des Testergebnisses in einem Vektor. Sie soll nicht weiter betrachtet werden.


[ nach oben ]

Fehlererkennung

Doch wie findet nun die eigentliche Fehlererkennung statt? Nun, wie oben schon besprochen, wurden sämtliche Assert-Methoden so entworfen, dass Sie bei negativen Tests eine Exception werfen. Der Schlüssel zur Protokollierung liegt folglich in der Methode run() der Klasse TestCase. Folgende Verfeinerung der oberen Definition von TestCase verdeutlicht diese Funktion:

01 public void run(TestResult result) {
02   Result.startTest(this);
03   
04   setUp();
05   
06   try {
07     runTest();
08   
09   } catch(AssertionFailedError e1) {
10     result.addFailure(this.e1);
11   
12   } catch(Throwable e2) {
13     result.addError(this, e2);
14 
15   } finally {
16     tearDown();
17   
18   }
19 }
code5.java

Codebeispiel 5


Wir erkennen also, dass die Aufrufe aller Tests durch separate try-catch-Blöcke voneinander gekapselt sind. Dadurch sichert uns JUnit einerseits zu, dass alle Tests voneinander unabhängig durchgeführt werden können, andererseits wirken sich auch nicht erwartete Fehler nicht negativ auf den Ablauf von folgenden Tests aus. JUnit durchläuft demnach immer alle (!) durchzuführenden Tests, ohne Rücksicht auf die Ergebnisse der zuvor vorangegangenen.


[ nach oben ]

Behauptungen (Assert)

Im oberen Teil haben wir einige Male über die sogenannten Behauptungen gesprochen, ohne eigentlich zu wissen wie diese aussehen. JUnit stellt dazu die Klasse Assert zu Verfügung. Mit dieser Klasse kann eine Vielzahl von Behauptungen aufgestellt werden.

Dabei benutzen wir diese Klasse während des Verfassens eines Tests, um einen Sachverhalt vorauszusetzen bzw. anzunehmen. Folglich stellen wir eine Annahme auf, die besagt, dass der durchgeführte Test dann erfolgreich verlaufen ist, wenn diese Annahme nach Ablauf des Tests zutrifft.

JUnit stellt uns dabei die folgenden Annahmen zur Verfügung:
Bei diesen Behauptungen handelt es sich immer um statische Methoden der Klasse Assert, welche im negativen Fall eine AssertionFailedError Exception werfen. Trifft die vorher definierte Annahme nach der Ausführung eines Tests nicht zu, so ist dies ein Zeichen für einen Fehler. Folgend einige Beispiele für aufzustellende Behauptungen:

01 Assert.assertTrue(expected.equals(result));
02 Assert.assertEquals(foo, coo);
03 Assert.assertEquals("foo coo test", foo, coo);
code6.java

Codebeispiel 6




... [ Seminar "JUnit" ] ... [ Inhaltsverzeichnis ] ... [ zurück ] ... [ weiter ] ... [ nach oben ] ...

valid html4 logo Code generated with AusarbeitungGenerator Version 1.1, weblink