Ein Beispiel
Übersicht: Ein Beispiel
Klasse Money
Nachdem wir einige der Grundprinzipien von JUnit besprochen haben, möchten wir nun anhand eines kleinen Beispiels die Funktionalität verdeutlichen. Wir werden im weiteren Verlauf eine Klasse erstellen, die folgende Kriterien erfüllen soll:
- Speicherung von verschiedenen Geldbeträgen mit
- der Unterstützung für verschiedene Währungen (vorerst nur eine Währung) und
- der Möglichkeit verschiedene Beträge zu addieren.
An dieser Stelle rufen wir uns noch einmal das Grundprinzip von JUnit zur Erinnerung: Erst testen (!), dann Programmcode verfassen. Demnach machen wir uns erst Gedanken darüber, welche Anforderungen an die Klasse Money zu stellen sind und bilden daraus einen simplen Testfall. Die Anforderung könnte in diesem Fall z.B. wie folgt aussehen:
- Zwei Beträge: 12 und 14 Euro ergeben addiert 26 Euro.
Der entsprechende Testfall würde in Javacode wie folgt aussehen:
01 public class MoneyTest extends TestCase {
02 public void testSimpleAdd() {
03 Money m12EUR = new Money(12, "EUR");
04 Money m14EUR = new Money(14, "EUR");
05
06 Money expected = new Money(26, "EUR");
07 Money result = m12EUR.add(m14.EUR);
08
09 Assert.assertTrue(expected.equals(result));
10 }
11
12 // dient zur Identifikation
13 public MoneyTest(String name) {
14 super(name);
15 }
16 }
|
code7.java |
Codebeispiel 7
In den ersten beiden Zeilen unserer kleinen Testroutine testSimpleAdd haben wir zwei Geldbeträge instanziiert. Weiterhin haben wir in den nächsten beiden Zeilen das Ergebnis auf zwei verschiedene Arten beschrieben: erstens als den Betrag von 26 EUR, zweitens als die Addition der beiden Beträge oberhalb.
Die eigentliche Behauptung wurde erst in der letzten Zeile des Tests aufgeführt: wir gehen davon aus, dass der Test auf Gleichheit wahr ist.
Ausgehend von dieser Testroutine können wir nun die Klasse Money verfassen:
01 public class Money {
02 private double amount;
03 private String currency;
04
05 public Money(double amount, String currency) {
06 this.amount = amount;
07 this.currency = currency;
08 }
09
10 public double getAmount() { return this.amount; }
11 public String getCurrency() { return this.currency; }
12
13 public Money add(Money oMoney) {
14 return new Money(this.amount + oMoney.getAmount(), this.currency);
15 }
16 }
|
code8.java |
Codebeispiel 8
Da die obere Testroutine die equals-Methode unserer Money-Klasse aufrufen wird, müssen wir die von Object geerbte Variante von equals überschreiben. Ein Test auf gleiche Referenzen würde in diesem Fall keinen Sinn machen. Wie sollen jedoch die Anforderungen an diese Methode in der Klasse Money aussehen? Hierbei sind wir wieder bei dem oben erwähnten Grundprinzip. Definieren wir also:
Das an die equals-Methode übergebene Objekt
- darf nicht Null gleichen,
- muss sich selbst gleichen,
- muss einem neuem Objekt mit dem gleichem Betrag und der gleichen Währung gleichen und
- darf nicht einem anderen Objekt mit unterschiedlicher Währung/Betrag gleichen.
Die sich aus diesen Behauptungen ergebende Testroutine würde wie folgt aussehen:
01 public void testEquals() {
02 Money m12EUR = new Money(12, "EUR");
03 Money m14EUR = new Money(14, "EUR");
04
05 Assert.assertTrue(!m12EUR.equals(null));
06 Assert.assertEquals(m12EUR, m12EUR);
07 Assert.assertEquals(m12EUR, new Money(12, "EUR"));
08 Assert.assertTrue(!m12EUR.equals(m14EUR));
09 }
|
code9.java |
Codebeispiel 9
Fixtures
Wie zu erkennen ist findet schon in diesem kleinem Testbeispiel Codeverdopplung statt: die Instanzen m12EUR und m14EUR wurden in beiden Testfällen deklariert. JUnit bietet uns hierzu eine weitere Hilfe an: die sogenannten Fixtures.
Fixtures definieren dabei Objekte, die in mehreren Tests verwendet werden können. Sie werden vor jedem Testlauf durch den Aufruf der Methode setUp() initialisiert. Dadurch können wir davon ausgehen, dass jeder Testfall mit genau den Ausgangswerten arbeitet, wie von uns vorgesehen. Unsere Tests der Klasse Money ergeben sich nach der Erweiterung um Fixtures zu:
01 import junit.framework.*;
02
03 public class MoneyTest extends TestCase {
04 private Money f12EUR;
05 private Money f14EUR;
06
07 protected void setUp() {
08 this.f12EUR = new Money(12, "EUR");
09 this.f14EUR = new Money(14, "EUR");
10 }
11
12 public void testSimpleAdd() {
13 Money expected = new Money(26, "EUR");
14 Money result = this.f12EUR.add(this.f14EUR);
15
16 Assert.assertTrue(expected.equals(result));
17 }
18
19 public void testEquals() {
20 Assert.assertTrue(!this.f12EUR.equals(null));
21 Assert.assertEquals(this.f12EUR, this.f12EUR);
22 Assert.assertEquals(this.f12EUR, new Money(12, "EUR"));
23 Assert.assertTrue(!this.f12EUR.equals(this.f14EUR));
24 }
25 }
|
code10.java |
Codebeispiel 10
Ausgehend vom Test auf Gleichheit kann nun auch Money.equals implementiert werden:
01 public boolean equals(Object aObject) {
02 if(aObject instanceof Money) {
03 Money aMoney = (Money) aObject;
04
05 return aMoney.getCurrency().equals(this.currency) &&
06 aMoney.getAmount() == this.amount;
07 }
08
09 return false;
10 }
|
code11.java |
Codebeispiel 11
Wir sind hier nun an einem Punkt angelangt, an dem die ersten beiden Tests erfolgreich ausgeführt werden können. Die Testumgebung kann dabei entweder textbasierend oder als Swinganwendung aufgerufen werden. Wir erweitern dazu unsere Testklasse um die folgende Funktion:
01 public class MoneyTest extends TestCase {
02 // ...
03
04 public static void main(String[] args) {
05 junit.swingui.TestRunner.run(MoneyTest.class);
06 //junit.textui.TestRunner.run(MoneyTest.class);
07 }
08 }
|
code12.java |
Codebeispiel 12
Unterhalb folgt ein Screenshot des erfolgreichen Testverlaufs.
Code generated with AusarbeitungGenerator Version 1.1, weblink