21.11.2010

Red October Baits - Tubes

Für die kommende Woche auf den Bodden werden die ersten Köder gesichtet. Auf jeden Fall werden die Monster Tubes von Red October Baits mit auf dem Boot sein. Vielleicht auch ein paar von den Big Sexy Tubes...








Mit den passenden Hakensystemen sicherlich eine Waffe für die hungrigen Boddenfische ;-)



15.11.2010

JUnit - Testing Framework für Komponententests

JUnit dient dem Entwickler als Framework für das Testen von geschriebenem Code. In den meisten Fällen wird JUnit als Framework für das Testen von einzelnen Modulen genutzt.
Das Testen von geschriebenem Code dient der Qualitätssicherung des gesamten Projektes. Dabei existieren unterschiedliche Metriken, wie viel und vor allem was in welchem Umfang getestet werden soll.
In der Regel sollten die Tests geschrieben werden bevor das eigentliche Modul entwickelt wird. Damit ist eine gründliche Auseinandersetzung mit den Anforderungen gegeben und der Entwickler gerät nicht in Versuchung nur den meist genutzten Pfad durch die Applikation zu testen.

Für das Beispiel wird ein Modul erstellt, welches eine kleine Benutzeranmeldung simuliert. Der Einfachheit halber werden die Daten im ersten Schritt nur lokal zur Verfügung stehen und werden mit Beenden des Programmes wieder gelöscht. Der Logout nach der Durchführung der unterschiedlichen Aktionen wird ebenfalls automatisiert durchgeführt.

Somit ergeben sich insgesamt 4 unterschiedliche Pfade, die getestet werden müssen.
  1. Login - Login [Login failure]
  2. Login - List all user - Logout
  3. Login - Create user - Create user[Conflict]
  4. Login - Create user - Logout
Diese vier Pfade können vor der eigentlichen Implementierung in den entsprechenden Tests getestet werden. Einzig die Schnittstelle für die Durchführung der Operationen muss dafür bekannt sein.


Mit diesen Informationen können alle Testfälle bereits implementiert werden.

Installation von JUnit

Die Installation von JUnit gestaltet sich sehr einfach. Es gibt zwei unterschiedliche Wege zur erfolgreichen Installation:
  1. Einbinden als bereits vordefinierte Bibliothek aus Eclipse
  2. Einbinden als externe Referenz auf das entsprechende JAR-File
Um unabhängig von der Entwicklungsumgebung zu sein, ist Möglichkeit zwei die deutlich bessere Wahl. Zumal für das automatisierte Testen mit Ant zu einem späteren Zeitpunkt die Bilbiothek als JAR-File auf dem Classpath vorliegen muss.
Die aktuelle Bibliothek (zum Zeitpunkt dieses Artikels Versioon 4.8.2) kann über die JUnit Webseite bezogen werden. Diese wird unter Eclipse dem Projekt hinzugefügt und in den Classpath eingebunden


Nach diesem Schritt stehen alle erforderlichen Klassen zur Verfügung und der Test kann implementiert werden.

Implementierung des Tests

Für die Implementierung wird folgender Workspace aufgesetzt.





Die Implementierung des Interfaces entspricht dem UML Diagramm weiter oben. Damit können die entsprechenden Testmethoden implementiert und somit die Bedingungen für die konkrete Implementierung des User-Managers festgelegt werden. 


Für die Implementierung des Testfalls wird eine neue Klasse angelegt.





Die einzelnen Methoden testen die Funktionalität des UserMgr. Zusätzlich werden Methoden für Aufgaben vor jedem Test und nach jedem Test definiert.



Mit Hilfe der Annotationen kann der Test leicht konfiguriert werden. Die Annotation org.junit.Before definiert eine Methode, die vor jedem Test ausgeführt wird. Mit org.junit.After wird eine Methode definiert, die nach der Durchführung eines jeden Tests ausgeführt werden kann.
Zusätzlich könnte der Test noch mit den Annotationen org.junit.BeforeClass und org.junit.AfterClass erweitert werden. Diese Annotationen können an statischen Methoden definiert werden und erlauben es die Methoden als statische Methoden beim Laden der Klasse und als letzte Aktion nach Testende auszuführen.

Die einzelnen Methoden des Tests werden mit org.junit.Test gekennzeichnet. Diese Annotation kann sowohl auf Klassenebene, als auch auf Methodeneben genutzt werden. Wird die Methode auf Klassenebene genutzt, dann wird jede Methode als Testmethode angesehen. Auf Methodenebene kann deutlich detaillierter gesteuert werden, welche Methode als Testmethode genutzt wird.
Das Exceptionhandling kann ebenfalls getestet werden. Dafür kann der Annotation org.junit.Test ein weiteres Attribut in Form der erwarteten Exception mitgegeben werden. Der Test wird fehlschlagen, sobald diese Exception nicht auftritt und nur dann erfolgreich sein, wenn die Exception auftritt.

Um erstellten Code effizient zu testen, wird der Entwickler immer Wissen aus der Implementierung mit einbringen und sogenannte Whitebox-Tests durchführen. Daher ist es sinnvoll an dieser Stelle die Implementierung der Klasse durchzuführen. Diese wird für das Beispiel bewusst einfach gehalten.

Für die Verwaltung der Nutzer werden zwei private Variablen deklariert, welche nach außen hin nicht sichtbar sein sollen. Daher erfolgt der Zugriff nicht über Getter- / Setter-Methoden.


Die eigentliche Implementierung stellt nun die Möglichkeit bereit einen Nutzer in die Liste der registrierten Nutzer aufzunehmen, sich einzuloggen und die Liste der eingeloggten Nutzer auszulesen.



Nach der Implementierung des Grundgerüstes werden die Testmethoden konkret implementiert. Um die Testmethoden effizient und sinnvoll zu implementieren ist ein wenig Wissen über die eigentliche Implementierung notwendig. Die Daten über die angemeldeten und verfügbaren Nutzer werden intern in einer Map verwaltet. Der Einfachheit halber werden die Daten im Klartext abgelegt. Um sinnvoll testen zu können müssen aber vor einem Test bereits Daten in dieser Map vorhanden sein.
Diese Daten können auf unterschiedliche Wege in die Map eingefügt werden. Zum einen können die Funktionen des Managers genutzt werden und zum anderen können die Daten per Reflection-API gesetzt werden.

Aus meiner Sicht ist der zweite Weg, der Weg über die Reflection-API zu bevorzugen. Damit wird keine Funktionalität für das Bereitstellen der Testdaten genutzt und ungetestet eingesetzt.


Damit sind alle Vorraussetzungen erfüllt um die Testfälle zu implementieren.


Innerhalb der Testfälle kann mit Hilfe der Klasse org.junit.Assert detailliert getestet werden welche Bedingungen erfüllt sein müssen, damit der Test erfolgreich verläuft. Dabei sollten Extremwerttests nicht vernachlässigt werden, da diese durchaus Fehler in der Implementierung aufdecken können.

Die Ausführung des Tests kann einfach durch einen Rechtsklick auf die Methode und das Wählen des "Run As" Commands durchgeführt werden.



Auf der Konsole sind dann zum einen die Meldungen zu sehen, die in der Implementierung ausgegeben worden sind und zum anderen die optische Bestätigung, dass die Tests positiv verlaufen sind.



Damit können die einfachen Testfälle bereits abgedeckt werden. JUnit stellt aber auch Werkzeuge für die Überprüfung von aufgetretenen Exceptions bereit. Diese können mit Hilfe des Attributes expected in der Annotation @org.junit angegeben werden.



Tritt diese Exception während der Ausführung des Tests nicht auf, so gilt der Test automatisch als fehlgeschlagen.

Ich hoffe, ich konnte mit dieser kleinen Einführung das Interesse an JUnit wecken.

Der Quellcode kann als Eclipse-Projekt bei Mediafire heruntergeladen werden.