Im ersten Beitrag dieser Serie ging es um den Nutzen und die Vorurteile von Unit Tests . Dieser Blog Post soll JUnit4, die neuste Version des beliebten Java Unit Testing Frameworks vorstellen.
In dieser Serie möchte ich beispielhaft ein Adressbuch bauen, dass neben eigenen Adressen auch Kontakte aus Twitter, Facebook & Co. importieren kann – ggf. habt Ihr ja auch Ideen oder Anregungen, um bestimmte Frage- oder Problemstellungen zu diskutieren, dann passe ich die Anforderungen entsprechend an.
Für die Programmierung nutze ich die Eclipse IDE in der Version 3.7 (Indigo) – ich möchte explizit eine moderne IDE benutzen, um die Möglichkeiten dieser Werkzeuge in Bezug auf Test First und Refactoring zeigen zu können. Zusätzlich verwende ich Maven3 für die Konfiguration des Projekts. Ich benutze Maven immer von der Kommandozeile, weil ich das Eclipse Plugin für Maven nicht mag – es steht aber jedem frei sich damit rumzuärgern. Meine JVM ist eine HoSpot 64-bit in der Version 1.6.0_26 unter Mac OS X Lion.
Schritt 1: Projekt anlegen und initialisieren
In der Konsole wechselt man in das Workspace Verzeichnis von Eclipse und gibt folgendes Kommando ein:
mvn archetype:generate
-DarchetypeGroupId=org.apache.maven.archetypes
-DarchetypeArtifactId=maven-archetype-quickstart
-DgroupId=de.codecentric.addressbook
-DartifactId=addressbook
-Dversion=1.0-SNAPSHOT
-DinteractiveMode=false
Mit dem Archetype Plugin kann man ein Projekt auf Basis vordefinierter Templates erstellen. In diesem Fall nutze ich das Quickstart Template, um ein einfaches Java Projekt zu erstellen.
Als nächstes wechselt man in das Verzeichnis des neu erstellten Projekts addressbook und führt ein weiteres Maven Kommando aus:
mvn eclipse:eclipse
Damit ruft man das Eclipse Goal des Eclipse Plugin von Maven auf und erzeugt ein Eclipse konformes Projekt auf Basis des Maven POM , das wir im ersten Schritt angelegt haben.
In Eclipse importieren wir das Projekt über File -> Import -> General -> Existing Project into Workspace und wählen dann das addressbook Verzeichnis aus.
Fertig ist unser Projekt inklusive der Maven typischen Verzeichnisse src/main/java für die Java Sourcen unserer Applikation und src/test/java für die Testklassen. Die Trennung von Applikations- und Test Code ist eine Best Practice, die von Maven automatisch umgesetzt wird.
Schritt 2: JUnit einbinden
Wir binden JUnit über eine neue Abhängigkeit in der pom.xml ein. Aktuelle Versionen schaue ich dafür immer auf mvnrepository.com nach. Die aktuelle Version von JUnit zum Zeitpunkt dieses Artikels war 4.8.2 – das entsprechende dependency Tag kann man sich von der Webseite kopieren und zu den Dependencies in der pom.xml hinzufügen:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
</dependency>
Mit
mvn eclipse:eclipse
auf der Kommandozeile und einem Refresh (F5) auf dem Eclipse Projekt ist die neue Abhängigkeit eingebunden.
Schritt 3: Der erste JUnit Test
In den Test Sourcen legen wir im Paket de.codecentric.addressbook eine Klasse mit dem Namen AddressBookTest an.
Als Namenskonvention sollte man den Testfall immer so nennen wie die zu testende Klasse mit dem angehängten Wort Test.
Die Testklasse sollte im gleichen Paket wie die zu testende Klasse liegen, allerdings im Verzeichnis src/test/java.
Zunächst möchte ich dem Adressbuch Kontakte hinzufügen können. Dafür lege ich eine entsprechende Test Methode im Testfall an.
Als Namenskonvention sollten Testmethoden immer mit dem Wort should beginnen und dann die Erwartungshaltung an den Testfall beschreiben. Beispielsweise shouldAddContact als Name für den Testfall, der das Hinzufügen von Kontakten überprüft.
Beim Erstellen des Tests hilft Eclipse dabei die benötigten Applikationsklassen automatisch mit zu generieren.
Wie man in obigem Screenshot sieht, zeigt Eclipse in der ersten Zeile der Testmethode einen Fehler an, weil die Klasse AddressBook, die getestet werden soll, nicht existiert. Mit Ctrl-1 öffnet man das gezeigte Kontextmenü und kann die Klasse über „Create class…“ erzeugen. (Im Dialog darauf achten den Source Folder auf src/main/java zu ändern)
Mit gleicher Funktion können auch Methoden in einer Klasse hinzugefügt werden. In obigen Beispiel lege ich die Methode addContact() an, damit man dem AddressBook auch Contact Objekte hinzufügen kann. Eclipse erkennt automatisch die Parameter Typen und return Typ und deklariert diese entsprechend. So erzeugt man den eigentlichen Applikationscode quasi „nebenbei“.
Danach testen wir, ob der Kontakt auch wirklich dem Adressbuch hinzugefügt wurde.
Testfälle sollten immer nach dem AAA-Prinzip aufgebaut sein: Arrange-Act-Assert, d.h. im ersten Schritt sollte das Test-Szenario aufgebaut, danach die zu testenden Aktionen durchgeführt und zuletzt die Annahmen überprüft werden.
Jeder Testfall (Testmethode) sollte nur genau ein Verhalten überprüfen.
Das Überprüfen erfolgt über so genannte assert-Methoden, die in der Klasse org.junit.Assert enthalten sind und über einen statischen import einfach zugänglich gemacht werden können.
Bei den Asserts immer eine Fehlermeldung als ersten Parameter mitgeben, das hilft Fehler schneller zu interpretieren.
Unsere fertige Testmethode sieht jetzt wie folgt aus:
1@Test
2public void shouldAddContact() {
3
4 // Arrange
5 AddressBook addressBook = new AddressBook();
6 Contact contact = new Contact();
7
8 // Act
9 addressBook.addContact(contact);
10
11 // Assert
12 assertEquals("The adressBook should contain 1 contact", 1,
13 addressBook.size());
14}
Schritt 4: Test ausführen und fixen
Mit dem Shortcut Ctrl-F11 führt man den Test aus dem Code heraus aus und das JUnit Plugin von Eclipse zeigt das Ergebnis des Tests an:
Der rote Balken symbolisiert einen fehlgeschlagenen Test und in der View werden fehlgeschlagener Testfall, Fehlermeldung und die Werte der Assertion angezeigt, so dass man als Entwickler direkt einen Überblick über die Ursache des Fehlschlags hat. Über die View kann man per Doppelklick auf den entsprechenden Fehler direkt zur Testmethode navigieren.
Beim Test First Ansatz oder Test-Driven-Development (TDD) implementiert man die Funktionalität schrittweise an Hand der Testfälle. Man erstellt wie in diesem Fall einen Testfall für die gewünschte Funktionalität und implementiert dann die minimale Funktionalität, um die Testkriterien zu erfüllen (grüner Balken).
In unserem Fall erweitern wir die von Eclipse generierte AddressBook Klasse wie folgt, um das Hinzufügen von Kontakten einfach zu realisieren:
1/**
2* Adressbuch zur Verwaltung von Kontakten.
3*/
4public class AddressBook {
5
6 /** Liste mit den Kontakten des Adressbuchs */
7 private List contacts = new ArrayList();
8
9 /**
10 * @param contact Der Kontakt der dem Adressbuch
11 * hinzugefügt werden soll.
12 */
13 public void addContact(Contact contact) {
14 contacts.add(contact);
15 }
16
17 /**
18 * @return Anzahl der Kontakte im Adressbuch.
19 */
20 public int size() {
21 return contacts.size();
22 }
23}
Das erneute Ausführen unseres Testfalls führt zu folgendem Ergebnis:
Der Test war erfolgreich und die gewünschte Funktion ist implementiert. Um die Tests ohne Eclipse mit Maven auf der Kommandozeile auszuführen, gibt man im Projektverzeichnis das Kommando mvn test ein. In der Ausgabe erscheint dann folgender Abschnitt:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running de.codecentric.addressbook.AddressBookTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.08 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
Ausblick
Nachdem wir unseren ersten Testfall mit einem Test First Ansatz erstellt haben, werde ich im nächsten Teil dieser Serie zeigen wie man den Code schrittweise über neue Testfälle erweitert und mit Hilfe von Refactoring verbessert. Zudem werde ich erweiterte Features von JUnit wie parametrisierte Tests und das Testen von Exceptions beschreiben.
Weitere Beiträge
von Mirko Novakovic
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog-Autor*in
Mirko Novakovic
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.