Anatol Zund smarter living

5Sep/070

Junit 4.1

Das Referat über JUnit habe ich in Zusammenarbeit mit Mircea Dumitru geschrieben.
Referat als PDF: JUnit_4_1.pdf

JUnit in einem Satz

JUnit ist ein Java-Framework für die Erstellung von Unit Tests

Definition von JUnit

JUnit ist ein Framework zum Testen von Java-Programmen, das besonders für automatisierte Unit-Tests einzelner Units (meist Klassen oder Methoden) geeignet ist. Es basiert auf Konzepten, die ursprünglich unter dem Namen SUnit für Smalltalk entwickelt wurden.

Einleitung

Warum Testen?

In der heutigen Zeit, wo Softwareprodukte immer komplexer werden, ist vor allem die Qualität einer Software sehr wichtig. Da aber komplexe Software in begrenzter Zeit nur unvollständig erfassbar und realisierbar ist enthält jede Software Fehler.
Um diese Fehler zu aufzudecken werden Tests notwendig, die eine teilweise hohe Softwarequlität sicherstellen können.
Ziel eines Tests ist somit eine Software mit der Absicht zu prüfen, Fehler zu finden.
Ein Test sollte:

  • Fehler so früh wie möglich finden
  • unabhängig erfolgen
  • mehr bringen als kosten
  • automatisiert wiederholbar sein
  • möglichst zeitnah zur Programmierung sein
  • Spaß machen

Ein Test sollte nicht:

  • keine Fehler finden

Somit kann ein Test nicht die Korrektheit eines Software beweisen, sondern nur die Anwesenheit von Fehlern.

Softwaretestarten

Tests können bzgl. eines Testobjekts in verschiedene Testarten klassifiziert werden:

  • Unit –bzw. Modul Tests
  • Integrationstests
  • Performance Tests
  • Funktionale –und Akzeptanz Tests

Unit –bzw. Modul Tests

Unit –bzw. Modul Tests dienen zur Verifikation der Korrektheit der einzelnen Softwarebausteine (Module; je nach Programmiersprache z. B. Klassen). Durch Ablauf aller Testfälle soll nach Programmfehlern gesucht werden. Hierzu wird ein ausführbarer Code erzeugt der die einzelnen Testfälle durchspielt und die Ergebnisse mit den erwarteten Werten vergleicht. Dabei prüft jeder Testfall immer nur ein mögliches Verhalten des Moduls ab, um hinterher genau feststellen zu können, wodurch ein Fehler erzeugt wurde.
Unit Tests sollten zeitnah zur Programmierung erstellt und nach jeder Programmmodifikation ausgeführt werden.

Integrationtests

Integrationstests prüfen die kortrekte Interaktion voneinander abhängiger Komponenten in einem komplexen System. Dazu müssen die zu prüfenden Komponenten den Unit-Test erfolgreich abgeschlossen´haben um zu zeigen, dass sie isoliert fehlerfrei funktionieren.

Performance Tests

Performance Tests dienen dazu das Verhalten einzelner Module oder Systeme bezüglich einer definiterten Hardwareumgebung zu Testen. Im Mittelpunkt steht dabei, ob das System die vom Kunden gewünschte Reaktionszeit einhält und auch unter hoher Auslastung keine Fehler produziert.

Funktionale Tests

Funktionale Tests dienen dazu, die vom Kunden gewünschte Funktionalität des Systems unter Real-Bedingungen zu prüfen. Dabei wird getestet ob das entwickelte System den Anforderungen des Auftraggebers oder späteren Benutzers entspricht.

Unit Testarten

Die weitere Klassifizierung von Unit Tests basiert auf drei verschiedene Unit Testarten:

  • Logischer Unit Test
  • Integrations Unit Test
  • Funktionaler Unit Test

Logischer Unit Test

Der Logische Unit Test überprüft nur einzelne Methoden bestimmter Klassen eines Softwaresystems.

Integrations Unit Test

Der Integrations Unit-Test überprüft das Zusammenspiel zwischen den einzelnen Komponenten eines Softwaresystems.

Funtionaler Unit Test

Der Funtionaler Unit-Test erweitert die Grenzen des Logischen Unit Tests und Integrations Unit Test so, dass Arbeitsabläufe getestet werden können. Die einzelnen Arten von Unit Tests können als White-Box-Test oder als Black-Box-Test durchgeführt werden.
White-Box-Test
Der White-Box-Test wird von den gleichen Programmieren entwickelt und durchgeführt wie das zu testende System selbst. Dabei besteht eine Kenntnis über die innere Struktur des Testobjektes.
Black-Box-Test
Der Black-Box-Test wird von speziellen Testabteilungen entwickdet und durchgeführt. Dabei besteht keine Kenntnis über den inneren Aufbau des zu testenden Objektes.

Herleitung der Testfälle

Die wichtigsten Bausteine, um erfolgreich zu Testen, sind die richtigen Testfälle. Es nutzt wenig, wenn man 20 Tests durchführt die im Endeffekt das Selbe Verhalten abprüfen, man dafür jedoch ein anderes Verhalten komplett übersieht. Für die Herleitung der Testfälle gibt es verschiedene Methoden, die wir hier auszugsweise aufzeigen wollen.

Äquivalenzklassenmethode

Bei der Äquivalenzklassenmethode werden Eingabeparameter eines Moduls oder einer Methode, die das gleiche Verhalten haben, in Klassen eingeteilt. Dazu wird die Spezifikation des Moduls oder der Methode analysiert.
Beispiel:
Man betrachtet ein Modul, dass nur Geldbeträge zwischen 0,01€ und maximal 500€ verarbeiten soll. Nun kann man alle Werte zwischen 0,01 und 500 zu einer Klasse zusammenfassen. Man wählt aus diesem Bereich dann einen Wert zum Testen aus. Ist der Test mit diesem Wert erfolgreich kann man davon ausgehen, dass er auch für alle anderen Werte der Klasse erfolgreich verläuft.
In diesem Beispiel kann man 3 Äquivalenzklassen bilden:

  • 0,01 <=x <= 500
  • x<=0
  • x>500

Prüft man aus diesen Bereichen jeweils einen Wert ab, kann man das Verhalten des Moduls testen.

Grenzwertanalyse

Die Grenzwertanalyse ist eine Erweiterung der Äquivalenzklassenmethode. Zusätzlich wird hier besonderes Augenmerk auf die Grenzen der Spezifikationen gelegt, da die Fehler sich in diesem Berech häufen.
In unserem Beispiel würde man die 3 Testfälle für die Äquivalenzklassen um folgende Testfälle erweitern:

  • -0,01
  • 0,00
  • 0,01
  • 500,00
  • 500,01

Vorgehensmethoden zur Softwareentwicklung

Testgetriebene Entwicklung

Von testgetriebener Entwicklung spricht man, wenn bei der Softwareentwicklung der Testplan vor der eigentlichen Implementierung erstellt wird. Während bei der klassischen Vorgehensweise der Test erst nach Fertigstellung des Moduls/Systems erstellt wird.
Nachteile wie mangelnde Testbarkeit, Zeitmangel, unzureichende Tests werden bei dieser Methode vermieden.
Testgetriebene Entwicklung arbeitet mit Tests auf zwei Ebenen.

Testen im Kleinen

Diese Tests beziehen sich auf die einzelnen Module des Systems. Hierbei wird der Testplan während der Entwicklung mit entwickelt. Man teilt die Implementierung in kleine Portionen auf z.B. in einzelne Methoden. Vor jeder Implementierung einer Methode werden die dazu gehörenden Testfälle erstellt. Dann wird (noch vor der Implementierung der Methode) ein Testlauf durchgeführt, der fehlschlägt. Nun wir die Methode implementiert und anschließend wieder getestet. Dies wiederholt sich so lange, bis alle Testfälle positiv beendet werden. Danach räumt man den Sourcecode auf und kümmert sich um die Kommentare. Ein abschließender Testlauf stellt sicher, dass man dabei keine Änderungen an der Funktion der Methode vorgenommen hat.

Testen im Großen

Diese Tests beziehen sich auf das gesamte System. Die Testfälle lassen sich aus den Spezifikationen ableiten und werden schon vor der Systemimplementierung aufgestellt.
Mit Hilfe dieser Tests kann geprüft werden, ob das System den Anforderungen des Kunden genügt.
Vorteile
Die Vorteile der testgetriebenen Entwicklung liegen in der verringerten Fehleranzahl (besonders bei Änderungen) und einer besseren Messbarkeit der Anforderungen. Da nur korrekte Module gespeichert werden, kann jeder Programmierer meistens auf „korrekte“ Module zugreifen um mit ihnen zu arbeiten. Des Weiteren fördert diese Vorgehensweise das „Think first – code later“-Prinzip, da man sich vor der Implementierung schon Gedanken über die Testfälle und damit auch über mögliche Probleme macht.

Weiterführende Tests

Dieses Kapitel widmet sich weiterführenden Tests, die auch über den Rahmen von JUnit hinausgehen.

Integrationstest (Cactus)

Cactus erlaubt es einem Integrationstests von Servlets und JSPs durchzuführen. Dabei wird das zu testende System auf dem Zielsystem ausgeführt um sein Verhalten in der Laufzeitumgebung zu prüfen. Es erweitert JUnit und verwendet im Moment noch JUnit 3.8.1.
Die Testfälle sind gleich aufgebaut wie bei JUnit selbst. Man kann die Tests sowohl manuell über die Komandozeile, als Plugin in einer IDE, oder im Webbrowser ausführen. Als Ergebnis bekommt man eine Zusammenfassung als XML-Datei die fehlgeschlagene Tests aufzeigt, oder aber eine Erfolgsmeldung zurückgibt.

Funktionale Tests (HTTPUnit)

HttpUnit ist eine Erweiterung für JUnit um automatisierte Website-Tests durchzuführen. Es ermöglicht die zurückgegebene Seite zu analysieren und z.B. dort enthaltenen Links zu folgen. Somit kann das Surf-Verhalten von Usern simuliert werden. Zusätzlich kann man auch Formulare oder JavaScript ausführen.

Load/Performance Testing (JMeter)

Bei JMeter handelt es sich um ein umfangreiches Testtool um Systeme unter großer Last zu testen. Hierzu erzeugt das Tool je nach Vorgabe eine große Anzahl von Threads, die alle auf das gleiche System zugreifen und misst dabei z.B. die Latenzzeit oder den Datendurchsatz. Dabei unterstützt es unter Anderem folgende Tests:

  • http, ftp
  • Datenbanken über JDBC
  • Java
  • JUnit
  • Webservices
  • LDAP

Da dieses Tool die Möglichkeit hat die Tests über mehrere Rechner zu verteilen kann damit auch ein Lasttest gegen größere Maschinen durchgeführt werden.

Load Testing (JUnitPerf)

Mit JUnitePerf kann man erweitert man JUnit um die Funktion Performance-Parameter abtesten zu können. So kann man vorgegebene Reaktionszeiten messen und testen. Zusammen mit einem Lastentest mit JMeter kann das System unter realen bzw. extremen Bedingungen getestet und somit verifiziert werden.