Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut...

22
Testen mit JUnit Softwareengineering Verfasser: Ronny Boost, Michael Künne BA Horb Studiengang: IT Jahrgang: 2003

Transcript of Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut...

Page 1: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Testen mit JUnit

Softwareengineering

Verfasser:

Ronny Boost, Michael Künne

BA Horb

Studiengang: IT

Jahrgang: 2003

Page 2: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 2 - 21.12.2005

Michael Künne

Inhaltsverzeichnis

1 Einleitung oder „Was ist JUnit“ ............................................................................ 3

2 Testarten ............................................................................................................. 4

2.1 Unit-Test....................................................................................................... 5

2.2 Integrationstest............................................................................................. 6

2.3 Blackbox-Test .............................................................................................. 6

2.4 Whitebox-Test .............................................................................................. 7

2.5 Zusammenfassung....................................................................................... 8

3 Testen mit JUnit .................................................................................................. 9

3.1 JUnit ............................................................................................................. 9

3.2 Installation ...................................................................................................12

3.3 Beispiel für einen Test.................................................................................12

3.4 Test Driven Development............................................................................15

3.4.1 Vorteile des TDD..................................................................................17

3.4.2 Nachteile des TDD...............................................................................17

3.5 konventioneller Softwareerstellung vs. TDD................................................18

4 Zusammenfassung.............................................................................................19

5 JUnit Erweiterungen ...........................................................................................20

6 Abbildungsverzeichnis........................................................................................21

7 Quellen ...............................................................................................................22

Page 3: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

1 Einleitung oder „Was ist JUnit“

Wenn man bei Wikipedia unter Junit schaut erhält

man folgende Definition: „Junit, (Jwnyt), auch Init,

eine altägyptische Göttin im Amduat (Totenbuch),

die farbige.“

Abbildung 1.1: altägyptischeGöttin Junit

Wenn man hingegen nach JUnit sucht erfährt man, dass es sich hierbei um „ein

Framework zum Testen von Java-Programmen“ handelt. Hierbei liegt besonderes

Augenmerk auf automatisierten Unit-Tests einzelner Klassen. Beim Testen im

Allgemeinen handelt es sich nicht um die fälschliche Annahme, zu verifizieren, dass

die Anwendung korrekt funktioniert, sondern um das Lokalisieren von Logikfehlern,

welche ausschließlich zur Laufzeit auftreten. Bei Unit-Tests, auch Komponententests

genannt, im Speziellen geht es um die Validierung einzelner Module einer Software,

zum Beispiel einzelner Klassen. Dass das Testen besonders in der

Softwareentwicklung einen sehr hohen Stellenwert haben sollte, sieht man bereits an

folgenden Zahlen [6]:

• 50-60 gefundene Fehler pro 1000 LOC während der Entwicklung

• Bis zu 3 Fehler pro 1000 LOC nach der Auslieferung

• Bei sicherheitskritischen Anwendungen ca. 0.5 Fehler pro 1000 LOC

• OB Wahl in Neu-Ulm 1995: 104% Wahlbeteiligung (tatsächlich 52%)

• Bluescreen

• Gepäckverteilungsanlage Flughafen von Denver: 16 Monate Verzögerung,

Schaden 550Mio USD

• Golfkrieg 1991: 28 Tote, fast 100 Verletzte wg. fehlerhafter

Uhrsynchronisation

Ronny Boost - 3 - 21.12.2005

Michael Künne

Page 4: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 4 - 21.12.2005

Michael Künne

2 Testarten

Ein Softwaretest bezeichnet in der Informatik ein mögliches Verfahren zur teilweisen

Verifikation und Validierung eines Programms. Der Test dient der Qualitätssicherung

einer neuen oder geänderten Software. Hierbei ist das Ziel das reelle Verhalten mit

Hilfe von Testfällen zu untersuchen und mit den erwarteten Ergebnissen zu

vergleichen und zu dokumentieren. Hierbei geht es um eine Aktivität der

Softwareentwicklung.

Natürlich gibt es nicht nur eine Art von Test mit der man alle Problemstellungen

abdecken kann.

Name Beschreibung

Application-Level-Test Test der gesamten Anwendung aus Benutzersicht in

einer Testumgebung.

(Öffentlicher) Betatest Testen einer Anwendung in produktiver Umgebung.

Performance-Test Testet das Verhalten der Anwendung unter

verschiedener Last (etwa Antwortzeiten,

Speicherverbrauch).

Skalierbarkeits-Test Ähnlich dem Performance-Test, mit Schwerpunkt auf

Veränderung der Leistung und

Ressourcenbeanspruchung bei der Variation einzelner

Parameter (zum Beispiel Zugriffe auf eine Datenbank).

Unit-Test Test der Bausteine einer Software (je nach

Programmiersprache zum Beispiel Klassen oder

Unterprogramme).

White-Box-Test Testen von Code durch möglichst umfassend

abgedeckte Parameterbereiche mit dem Ziel,

potenzielle Laufzeitfehler zu ermitteln (White-Box, da

Kenntnisse der internen Struktur für die

Parametererzeugung genutzt werden).

Black-Box-Test Testen von Code-Einheiten über spezielle Testfälle.

Die Grenze zum White-Box-Test ist fließend, aber es

steht mehr die richtige Verarbeitung von Eingaben im

Page 5: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 5 - 21.12.2005

Michael Künne

Mittelpunkt, weniger das Auffinden von Laufzeitfehlern.

Regression-Test Vergleich von Testläufen vor und nach der Änderung

von Code. Ergebnisse sollten sich nur geplant (etwa

als Folge eines Bugfixes) ändern.

Integration-Test Bezeichnet eine aufeinander abgestimmte Reihe von

Einzeltests, die dazu dient, welche dazu dient das

Zusammenspiel mehrerer von einander abhängiger

Komponenten zu testen. Tabelle 2-1: Zusammenfassung verschiedener Testmethoden.

2.1 Unit-Test

Unit-Tests sind Teil einer Softwareentwicklungsvorgehensweise, wie zum Beispiel

„Extreme Programming“. Mit ihrer Hilfe überprüft man die Korrektheit von Modulen

einer Software. Ein wichtiges Anwendungsgebiet ist an dieser Stelle das Refactoring.

Bei Refactoring handelt es sich um das Ziel Quellcode lesbarer zu machen. Um

dabei die Funktionalität im vollem Umfang weiterhin gewährleisten zu können

verwendet man Unit-Tests. Des Weiteren ist es ein integraler Bestandteil bei der

testgetriebenen Programmierung. Hier werden die Testfälle meist vor oder während

der eigentlichen Entwicklung der Software geschrieben und gewartet. Dadurch wird

ermöglicht, dass Tests automatisiert und reproduzierbar wiederholt werden können.

Mit Hilfe von Unit-Tests ist eine unmittelbare Rückmeldung für den Programmierer

möglich, ob das Programm den gewünschten Anforderungen entspricht und korrekte

Ergebnisse produziert oder nicht. Komponententests sind ein essentieller Bestandteil

der Qualitätssicherung und Softwareentwicklung.

Unit-Tests sind eine sehr geeignete Vorstufe zu Integrationstests, welche wiederum

dafür geeignet sind um eine Summe von mehreren Klassen in Abhängigkeit von

einander zu testen. Jedoch werden diese Integrationstests meist manuell

durchgeführt.

Page 6: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 6 - 21.12.2005

Michael Künne

2.2 Integrationstest

Da Software nur in den seltensten Fällen aus nur einer Methode besteht, ist es nötig

diese in Kombination miteinander zu testen um zu überprüfen, ob diese im

Zusammenspiel miteinander auch korrekt arbeiten. Hierfür werden Testszenarios

definiert, welche in der Lage sind nachzuweisen, dass die zwei oder mehr Methoden

korrekt und gemäß den Spezifikationen miteinander agieren. Als Methoden werden

hierfür meist Funktions- und Schnittstellentests verwendet. Da die Funktionstests

meist schon in den Unit-Tests verwendet werden, dienen sie an dieser Stelle zum

Überprüfen, ob die korrekten Komponenten verwendet werden. Die

Schnittstellentests werden wiederum dazu verwendet zum Überprüfen, ob zwischen

Komponenten verwendete Daten richtig sind.

Integrationstests sind jedoch nicht auf das Gesamtsystem festgelegt. Da mit der

Größe der Software auch der Testaufwand überproportional steigt, wird die Software

meist in einzelne Untersysteme eingeteilt, die einzeln getestet werden, welche im

Gesamtsystem auch wiederum nur als Komponente gesehen werden.

2.3 Blackbox-Test

Dabei betrachtet der Tester das Programm als Blackbox, d.h. der Tester ist nicht an

dem internen Verhalten und an der Struktur des Programms interessiert, sondern

daran, Umstände zu entdecken, bei denen sich das Programm nicht gemäß den

Anforderungen verhält.

Die Testdaten werden nur aus der Spezifikation (Aus-/Eingabeparameter sowie die

Funktion des Programms) abgeleitet, d.h. ohne spezielle Kenntnis der internen

Struktur.

Äquivalenzklassen Wie oben hergeleitet soll hier die Untermenge von Testfällen bestimmt werden, die

mit höchster Wahrscheinlichkeit Fehler enthält. Zur Bestimmung dieser Untermenge

sollte man wissen, dass ein gut ausgewählter Testfall zwei weitere Eigenschaften

haben sollte:

Page 7: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 7 - 21.12.2005

Michael Künne

• er reduziert die Anzahl anderer Testfälle, die man entwickeln müsste um ein

vorgegebenes Ziel beim Testen zu erreichen

• er überdeckt eine große Menge anderer möglicher Testfälle, d.h. er sagt

etwas über die An- oder Abwesenheit von Fehlern für diesen speziellen Satz

von Eingabedaten aus

Letzteres bedeutet, wenn ein Testfall in einer Äquivalenzklasse einen Fehler

entdeckt, so erwartet man, dass alle anderen Testfälle in einer Äquivalenzklasse den

gleichen Fehler finden. Anders herum ausgedrückt, wenn ein Testfall den Fehler

nicht entdeckte, so erwarten wir, dass kein anderer Testfall in der Äquivalenzklasse

diesen Fehler findet.

Diese beiden Überlegungen führen zu einer Blackbox-Strategie, die als

Äquivalenzklassenbildung bekannt ist. Die zweite Bedingung dient zur Entwicklung

einer Menge von Bedingungen, die getestet werden sollen. Mit der ersten

Überlegung wird dann ein Minimalsatz von Testfällen definiert, der diese

Bedingungen vollständig erfasst.

2.4 Whitebox-Test

Die interne Struktur des Programms ist beim Whitebox-Test zentraler Dreh und

Angelpunkt der Untersuchung. Bei dieser Strategie definiert der Tester die Testdaten

mit Kenntnis der Programmlogik.

Beim Whitebox-Testen betrachtet man den Anteil des Programms (source code), der

durch die Testfälle ausgeführt oder angesprochen wird. Hierzu dienen folgende

Strategien [7]:

• Line coverage (Ausführung aller Anweisungen) Hier soll jede Anweisung im Programm wenigstens einmal ausgeführt werden.

Das Verhältnis von ausgeführten zu vorhandenen Anweisungen wird als C0-

Überdeckung bezeichnet. Bei 100% C0-Überdeckung führen die Testfälle jede

Anweisung mindestens einmal aus.

• Decision oder branch coverage Dies ist eine strengere Strategie für die Erfassung der Logik, bei der alle

Entscheidungen oder Sprünge ausgeführt werden. Bei diesem Verfahren

Page 8: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 8 - 21.12.2005

Michael Künne

müssen hinreichend viele Testfälle entworfen werden, so dass bei jeder

Entscheidung sowohl der THEN-Zweig als auch der ELSE-Zweig mindestens

einmal durchlaufen wird. Das Verhältnis von ausgeführten zu vorhandenen

Entscheidungspfaden (z.B. IF/ELSE-Zweige) wird als C1-Überdeckung

bezeichnet. Bei 100% C1-Überdeckung liefert jede Entscheidung mindestens

einmal TRUE und einmal FALSE. Man kann zeigen, dass diese Strategie

auch die Forderung nach der Ausführung eines jeden Befehls erfüllt.

2.5 Zusammenfassung

All diese Testverfahren sind in der Theorie sehr schön, jedoch werden sie nur zu

einem geringen Teil in der Praxis so eingesetzt. Am praktikabelsten bei diesen

Methoden sind die Komponenten- und Integrationstests. Sie sind am einfachsten zu

realisieren, sie sind kombinierbar, reproduzierbar und es gibt viele Hilfsprogramme,

die einem die Arbeit erleichtern können. In Java heißt hier das Zauberwort „JUnit“.

Page 9: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 9 - 21.12.2005

Michael Künne

3 Testen mit JUnit

Nun ist blindes „Drauflostesten“ vielleicht nicht besonders klug. Darum stellt sich die

Frage nach sinnvollen Kriterien für Softwaretests. Gute Deklarationen liefert die

Literaturrecherche [8]:

• Strikte Trennung des Testcodes vom Programmcode gewährleistet schlanke

Klassen und kleinere Softwarepakete zur Auslieferung.

• Testfälle sind vollkommen unabhängig voneinander ausführbar. Es gibt keine

festgelegte Reihenfolge oder … Abhängigkeiten der Testfälle untereinander.

• Das Ergebnis der Tests ist auf einen Blick eindeutig erkennbar, dadurch ist

keine Auswertung von Logfiles oder kryptischer Konsolenausgaben

notwendig.

3.1 JUnit

JUnit ist ein frei verfügbares, unter der IBM Public License stehendes Framework für

die Durchführung von Black-Box-Tests. Testfälle werden in eigenen Testklassen

kodiert und zu Testsuiten zusammengefasst. Somit ist die strikte Trennung des

Codes von Anwendung und Test sichergestellt. Diese Tatsache beinhaltet folgende

Vorteile:

• Bei Auslieferung der Software werden die Tests nicht mit ausgeliefert und

somit ist das Programm schlanker.

• Weitere, nicht mit der Anwendung vertraute Entwickler, können sich schneller

einarbeiten.

• Der Code der Anwendung bleibt selbst bei steigender Komplexität

übersichtlich.

Die grundlegende Einheit beim Testen mit JUnit ist der Testfall - in der Klasse

„TestCase“ gekapselt. Ergebnisse werden in „TestResult“ gespeichert. Die zentrale

Methode der Klasse „TestCase“ ist „TestCase.runTest(TestResult)“, die im Interface

„Test“ definiert wird. Zum Aufbau dieser Methode später mehr. Mehrere Testfälle

Page 10: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

werden zu Gruppen in der Klasse „TestSuite“ zusammengefasst. Das Besondere an

„TestSuite“ ist, dass sie ebenfalls das Interface „Test“ implementiert. Wird dann

„TestSuite.runTest(TestResult)“ aufgerufen, gibt die Klasse den Aufruf an alle

enthaltenen Testfälle weiter. Das funktioniert auch, falls eine Testsuite nicht nur

echte Testcases enthält, sondern wieder Testsuiten. So ist das hierarchische

Schachteln von Testfällen möglich.

In Abbildung 3.1 ist das Klassenschema zu sehen. Das Design-Pattern, welches das

„Test“-Interface und die beiden Klassen „TestCase“ und „TestSuite“ verbindet, heißt

Composite. Wie in der Abbildung zu sehen, ist das Framework mit drei zentralen

Klassen und einem Interface sehr übersichtlich, was die Einarbeitung verkürzt und

den Einsatz vereinfacht. Die gesamte Distribution hat zwar momentan elf Klassen

und drei Interfaces, aber von den zusätzlichen Klassen ist nur die „Assert“-Klasse

von ähnlich zentraler Bedeutung (und auch sie nur indirekt).

Abbildung 3.1: Aufbau der wichtigsten Klassen des JUnit-Frameworks [2]

Die Klasse Assert mit den wichtigsten Asserts: class Assert (parent class of TestCase) - static assertTrue() basic assert function (used to be assert())

Ronny Boost - 10 - 21.12.2005

Michael Künne

Page 11: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 11 - 21.12.2005

Michael Künne

- static assertEquals() for all primitive types and Object - static assertNull() for Object - static assertNotNull() for Object - static assertSame() for Object - static assertNotSame() for Object - static assertFalse() for boolean condition - static fail() make a test fail

Zurück zum Aufbau der Runtest-Methode. Sie ruft intern die folgenden drei

Methoden auf:

„setUp()“

„runTest()“

„tearDown()“

Alle drei Methoden sind leer implementiert und können vom Entwickler

überschrieben werden. „setUp()“ und „tearDown()“ erzeugen eine geeignete

Testumgebung beziehungsweise geben sie frei. Die Methode „runTest()“ dagegen

enthält die eigentlichen Tests.

Durch Reflection - eine Java-Technik, die es ermöglicht, zur Laufzeit die Methoden

einer Klasse abzufragen - ist es möglich in der Testklasse nur eine Reihe von

Methoden nach dem Schema „void testXXX()“ anzulegen statt „runTest()“ zu

überschreiben. Durch den Konstruktor „TestSuite(MyTestClass.class)“ werden dann

automatisch alle Testmethoden innerhalb der Testsuite durchgeführt. Die

Reihenfolge der Ausführung der test – Methoden ist dabei nicht festgelegt und spielt

insofern keine Rolle, da die Methoden der Anwendung unabhängig voneinander das

gleiche Ergebnis liefern sollen.

Page 12: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 12 - 21.12.2005

Michael Künne

3.2 Installation

Die Installation ist einfach: das heruntergeladene Zip-File entpacken (Download von

www.junit.org) und das dann verfügbare Jar-Archiv zum „CLASSPATH“ des

jeweiligen Systems hinzufügen bzw. in die IDE einbinden.

3.3 Beispiel für einen Test

Im folgenden Listing ist ein Beispiel zum Anlegen von „Person“ – Objekten zu sehen: Listing 1: Person.java 01: class Person { 02: private String iVname, iNname; 03: 04: public Person(String v, String n) { 05: iVname = v; 06: iNname = n; 07: } 08: 09: public boolean equals(Object o) { 10: Person p = (Person) o; 11: return p.getVname() == iVname && p.getNname() == iNname; 12: } 13: 14: public String getVname() { 15: return iVname; 16: } 17: 18: 19: public String getNname() { 20: return iNname; 21: } 22: 23: public void setVname(String v) { 24: iNname = v; 25: } 26: 27: 28: public void setNname(String n) { 29: iNname = n; 30: } 31: 32: public String toString() { 33: return iVname + " " + iNname; 34: } 35: }

Die Objekte der Klasse Person.java enthalten die

- Attribute:

Page 13: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 13 - 21.12.2005

Michael Künne

o iVname = Vorname.

o iNname = Nachname.

- Methoden:

o Getter und Setter für die Attribute.

o toString(), um aus Vor- und Nachname den vollständigen Namen

zusammenzusetzen.

und den Konstruktor, welchem alle o.g. Attribute übergeben werden.

Zum Testen der Methoden des Anwendungscodes dient die Klasse PersonTest.java. Listing 2: PersonTest.java 01: import junit.framework.*; 02: 03: public class PersonTest extends TestCase { 04: 05: private Person iAuthor,iAuthor2, iAuthor3, iTux, iTux2; 06: private String iName; 07: 08: public PersonTest(String name) { 09: super(name); 10: } 11: 12: public static void main(String[] args) { 13: junit.swingui.TestRunner.run(PersonTest.class); 14: } 15: 16: protected void setUp() { 17: iAuthor = new Person("Bernhard", "Bablok"); 18: iAuthor2 = new Person("Bernhard", "Bablok"); 19: iAuthor3 = new Person(null,null); 20: iAuthor3.setVname("Bernhard"); 21: iAuthor3.setNname("Bablok"); 22: iTux = new Person("Tux",null); 23: iTux2 = new Person("Tux",null); 24: iName = "Penguin"; 25: } 26: 27: public void testEquals() { 28: assertTrue(iAuthor.equals(iAuthor2)); 29: assertTrue(!iAuthor.equals(iName)); 30: assertTrue(iTux.equals(iTux2)); 31: } 32: 33: public void testSetName() { 34: assertEquals(iAuthor,iAuthor3); 35: } 36: 37: public void testGetNname() { 38: assertEquals(iAuthor.getNname(),"Bablok"); 39: } 40: 41: public void testToString() { 42: assertEquals(iAuthor.toString(), "Bernhard Bablok"); 43: }

Page 14: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

44: }.

Das “…Test” im Namen ist nicht zwingend erforderlich, aber um die eindeutige

Zugehörigkeit zur zu testenden Klasse sicher zu stellen ist es sinnvoll hinter den

ursprünglichen Klassennamen der Anwendung das Suffix “…Test“ anzuhängen.

Im Gegensatz hierzu ist die Benennung der Prüfmethoden fest vorgegeben: Diese

müssen immer der Form „testXXX“() entsprechen, wobei für XXX ein beliebiger

Name stehen kann, wiederum vorzugsweise der Name der zu testenden Methode.

Der Ablauf des Test beginnt durch den Aufruf der main(…)-Methode und des darin

enthaltenen Methodenaufrufs von run(…) wie oben beschrieben. In der Methode

setUp() wird eine Testumgebung mit diversen Testobjekten angelegt. Auf diesen

Testobjekten werden nun die Testmethoden ausgeführt. Sobald ein assert(…)

fehlschlägt unterbricht JUnit die Ausführung und signalisiert dies mit einem roten

Balken und der Angabe bei welchem Test dies passierte. Hier beispielsweise schlägt

der Test fehl. Der hier verwendete TestRunner zeigt die in Abbildung 3.2 dargestellte

Ausgabe:

Abbildung 3.2 JUnit in Aktion: Zwei Fehler wurden gefunden, in der unteren Hälfte der Stack Trace dazu. [2]

Ronny Boost - 14 - 21.12.2005

Michael Künne

Page 15: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Nach Bereinigung aller Fehler sieht das Ergebnis wie in Abbildung 3.3 aus:

Abbildung 3.3: Ein erfolgreicher JUnit-Lauf. [2]

Es dient also ein einfacher grüner oder roter Balken als Bestätigung für den Erfolg

bzw. Misserfolg des Testvorgangs.

Um nun diese Tests in einer TestSuite zu integrieren ist nicht mehr viel Aufwand

vonnöten: Listing 3: AllTests.java 01: import junit.framework.*; 02: 03: public class AllTests { 04: 05: public static Test suite() { 06: TestSuite suite = new TestSuite("Test for default package"); 07: suite.addTestSuite(PersonTest.class); 08: return suite; 09: } 10: }

3.4 Test Driven Development

In obigem Beispiel wurde der Test erst nach Erstellen der Klasse „Person.java“ für

die darin enthaltenen Programmteile implementiert. Eine andere Vorgehensweise

wäre die Überlegung der Test-First-Strategie. Dabei gilt es einen Test für eine Ronny Boost - 15 - 21.12.2005

Michael Künne

Page 16: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 16 - 21.12.2005

Michael Künne

Softwarekomponente - bei der objektorientierten Programmierung in der Regel

Klassen - vor der eigentlichen Komponente zu implementieren.

Der Entwickler einer Klasse ist sich in der Regel klar darüber, was er mit seiner

Klasse erreichen möchte. So entsteht eine Art Protokoll für die Anwendung der

Klasse. Und genau dieses Protokoll wird von einem Unit Test geprüft. Die zu

entwickelnde und zu testende Klasse wird dabei immer nur so weit ausprogrammiert,

wie es notwendig ist, um einen Test zu erfüllen. Nach jedem erfolgreichen Test wird

dann der entwickelte Code in kurzen Zyklen weiter verfeinert und erneut getestet, bis

dieser die Geschäftslogik erfüllt und in einem optimalen Zustand ist. Neudeutsch

spricht man hier von Refactoring. Der Vorteil dieses Verfahrens ist es, stets über

einen funktionierenden Code zu verfügen, der leicht automatisiert getestet werden

kann.

In der testgetriebenen Softwareentwicklung geht der Entwickler folgendermaßen vor:

- Der erste Schritt ist das Schreiben eines Tests für die zu erfüllende

Teilfunktion

- Der Code der Anwendung wird nun so geschrieben, um dem Test zu genügen

oder anders ausgedrückt: damit der Test fehlerfrei durchläuft.

- Während der Implementierung wird nun abwechselnd am Programm- bzw.

Testcode geschrieben, wodurch kleine Iterationen entstehen, welche in sehr

kurzen Zeitabständen (5 – 20 Minuten) erfolgen.

- Bevor der neu entstandene Code in das Gesamtsystem integriert werden darf,

müssen alle Tests fehlerfrei laufen.

Die hierbei immer wieder auftretende Reihenfolge beim Testen ist grün – rot – grün –

rot …, d.h. nach Schreiben des Tests kann dieser selbstverständlich noch nicht erfüllt

werden, da noch kein Code zum Erfüllen der Testbedingung vorhanden ist. Nun

schreibt der Entwickler so wenig Code wie möglich, um den Test zu erfüllen bis der

JUnit-Test als Ergebnis den oben erläuterten grünen Balken ausgibt. Dann beginnt

der Ablauf von vorne mit dem Schreiben eines Tests. Der bis dahin geschriebene

Programmcode wird durch diese kleinen Iterationen mit verfeinert und bei jedem

Ausführen der Tests wieder geprüft. Dadurch wird sichergestellt, bereits positiv

getesteten Code nicht wieder zu verschlechtern.

Page 17: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 17 - 21.12.2005

Michael Künne

3.4.1 Vorteile des TDD

• Das TDD zwingt den Entwickler dazu, sich während der Entwicklung einer

Klasse und speziell noch vor der Implementierung Gedanken über die

Nutzung der Klasse zu machen.

• Fehler in der Implementierung werden frühzeitig vermieden oder erkannt, was

bei der abschließenden Fehlersuche enorm Zeit und damit Geld einspart. Ist

die Software allerdings im fortgeschrittenen Zustand, ist der Fehler nur unter

großem Aufwand (also teuer) zu beheben.

• Code soll funktional bleiben, also nicht regressiven Einflüssen während der

weiteren Entwicklung unterliegen.

• Kein unnötiger Code im Programm.

3.4.2 Nachteile des TDD

• Es sind gute bis sehr gute Kenntnisse im Entwerfen und Implementieren von

Software zwingend erforderlich.

• „Ohne Disziplin kein Erfolg“. Weicht der Entwickler von der Vorgehensweise

der kleinen Iterationen ab – schreibt beispielsweise der Entwickler in einer

kreativen Phase drei Klassen ohne vorher Tests zu schreiben – ist die

Methodik sehr schwer wieder aufzunehmen.

Page 18: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

3.5 Konventionelle Softwareerstellung vs. TDD

Eine Gegenüberstellung von konventioneller Entwicklung in Abbildung 3.4 zu

testgetriebener Entwicklung in Abbildung 3.5 soll die Vorteile des Testcase Driven

Development (TDD) bezüglich Aufwand, Kosten und umgesetzter Anforderungen

verdeutlichen:

Abbildung 3.4: Konventioneller Projektablauf [3]

Abbildung 3.5: Testgetriebener Projektablauf [3]

Ronny Boost - 18 - 21.12.2005

Michael Künne

Page 19: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 19 - 21.12.2005

Michael Künne

4 Zusammenfassung JUnit eignet sich gut für nachvollziehbare, reproduzierbare Tests von

abgeschlossenen Einheiten (Units). Dadurch ist Refactoring des bereits

implementierten Codes begünstigt. Die prinzipielle Einfachheit mit der Tests

umgesetzt werden können, kombiniert mit beliebiger Erweiterbarkeit entsprechend

dem Wachstum des Programms ist die große Stärke von JUnit.

Es ist allerdings nicht das ultimative Werkzeug zur Behebung aller Fehler in Software

und deren Entwicklung, sondern stellt ein wichtiges zusätzliches Mittel, insbesondere

für die testgetriebene Softwareentwicklung und teilweisen Validierung bereits

vorhandener Projekte dar.

Im Hinblick auf das TDD sollte sich jeder Programmierer ernsthafte Gedanken über

seine Vorgehensweise beim Programmieren anstellen. Der Weg vom

„Drauflosprogrammieren“ zum strukturierten Vorgehen mittels Entwurf der wirklich

benötigten Funktionen vor dem ersten Zeichen Code ist ein Steiniger, aber

Lohnenswerter.

Page 20: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 20 - 21.12.2005

Michael Künne

5 JUnit Erweiterungen Projekt Beschreibung

StrutsTestCase Testen des JSP-Frameworks Struts.

JUnitX und XPTest Erweiterung auf Privat- und Protected-Klassen,

Integration in Together.

JUnit und TIBCO Integration in TIBCO Active Enterprise Application.

JUnit Test Generator Generierung von Testfällen.

Daedalus JUnit Extensions Ressourcen-Management für JUnit-Tests.

JFCUnit Unit-Tests für Swing-Applikationen.

JUnitPP Unter anderem Testdaten Repository,

Kommandozeilen-Argumente.

JSP TEST Testen von Java Server Pages.

JXUnit Trennt Testdaten und Testcode. Verwendet XML.

JUnitHelp Hilfe zu JUnit.

Joshua Regression-Testing mit JUnit.

JDepend Testen von Design-Metriken (misst die Komplexität der

Klassen).

JesTer Sucht Code, der nicht durch Tests abgedeckt wird.

HttpUnit Funktionstest von interaktiven, dynamischen

Webseiten.

JUnitEE Tests für J2EE-Anwendungen.

Cactus Testet Server-seitigen Java-Code.

UnitPerf Erweitert JUnit-Testklassen für Performance- und

Skalierungstests. Tabelle 5-1: JUnit Erweiterungen.

Page 21: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 21 - 21.12.2005

Michael Künne

6 Abbildungsverzeichnis Tabelle 2-1: Zusammenfassung verschiedener Testmethoden. 5

Abbildung 3.1: Aufbau der wichtigsten Klassen des JUnit-Frameworks [2] 10

Abbildung 3.2 JUnit in Aktion: Zwei Fehler wurden gefunden, in der unteren Hälfte

der Stack Trace dazu. [2] 14

Abbildung 3.3: Ein erfolgreicher JUnit-Lauf. [2] 15

Abbildung 3.4: Konventioneller Projektablauf [3] 18

Abbildung 3.5: Testgetriebener Projektablauf [3] 18

Tabelle 5-1: JUnit Erweiterungen. 20

Page 22: Testen mit JUnit · 1 Einleitung oder „Was ist JUnit“ Wenn man bei Wikipedia unter Junit schaut erhält man folgende Definition: „Junit, (Jwnyt), auch Init, eine altägyptische

Ronny Boost - 22 - 21.12.2005

Michael Künne

7 Quellen

[1] Frank Westphal „Testgetriebene Entwicklung“ 2005

[2] Bernhard Bablok „Reihenuntersuchung“;

Linux-Magazin Ausgabe 03/2002

[3] www.linuxenterprise.de 2004

[4] de.wikipedia.org

[5] „Das heilige Orakel“ www.google.de

[6] Robert Pintarelli Modul-Tests mit JUnit 2004

[7] Christian Aich, Robert Reeb Einführung in den Softwaretest 2004

[8] Barbara Beenen Rot-Grünes Wechselspiel 2004