Open Source im professionellen Einsatz
Linux-Magazin 08/2012
© koi88, 123RF

© koi88, 123RF

Testgetriebene Software-Entwicklung

Präziser Antrieb

Das Credo des Test Driven Development (TDD): Wer zuerst Tests schreibt und dann erst programmiert, erzeugt sauberen Code und geprüfte Programme. Wie das in Java und weiteren Sprachen geht, zeigt dieser Artikel, der auch die Vor- und Nachteile der Methode abwägt.

914

Programmieren macht Spaß. Der Entwickler schreibt ein paar Zeilen Code, und schon erscheint eine Grafik auf dem Bildschirm oder ein Roboter bewegt seinen Arm. Besonders im Bereich freier Software ist das die Herangehensweise fast jedes Programmier-Einsteigers.

Rot und Grün

Die Verfechter testgetriebener Programmierung predigen jedoch seit Jahren, dass so Software entsteht, die keine hohe Qualität aufweist. Die neue Lehre propagiert das Mantra "red, green, refactor" [1]. Diesem folgend schreibt der Programmierer erst einen Test. Der schlägt natürlich fehl – und weist damit gemäß Konvention den Status Rot auf. Im zweiten Schritt fügt der Entwickler den eigentlichen Code hinzu. Erfüllt dieser den vorher erstellten Test, wechselt der Status auf Grün. Dabei muss der Code zum Erfüllen der Testbedingung nicht zwingend bereits sauber geschrieben sein. Der letzte Schritt besteht aus Geradeziehen der Codestruktur, Umstrukturieren und Refactoring. Er muss allerdings unter Beachtung der geschriebenen Tests erfolgen: Der Status darf durch Refactoring nicht von Grün auf Rot wechseln.

Das angestrebte Ziel dieses Verfahrens: sauberer Code mit hoher Qualität. Der Entwickler hat nicht mehr einfach nur Ideen oder Ziele vor Augen, die er sofort in Code umsetzt. Stattdessen treibt ein mit Hilfe der Tests definiertes Korsett den eigentliche Code. Entsprechend heißt diese Vorgehensweise testgetriebene Entwicklung.

Die Überlegungen hinter diesem Verfahren, die Vorteile und auch die Nachteile, diskutiert dieser Artikel gegen Ende noch einmal ausführlich. Zunächst soll ein praktisches Beispiel die Vorgehensweise anschaulich machen.

Das Beispiel verwendet so genannte Unit-Tests. Dabei handelt es sich um sehr kleinteilige Tests, die nah am Code nur Bruchstücke oder Einheiten (Units) des Programms testen. Der Begriff testgetriebene Entwicklung bezieht sich so gut wie immer auf Units.

Werkzeuge für Unit-Testing existieren für praktisch jede Programmiersprache. Das folgende Beispiel könnte sich also jeder beliebigen Sprache bedienen. Da Java jedoch sehr verbreitet ist und für viele Entwickler gut lesbar, demonstrieren die folgenden Zeilen testgetriebene Entwicklung in dieser Sprache.

Schritt für Schritt

Die Programmieraufgabe besteht darin, mit dem Avatar-Service Gravatar zu kommunizieren und einer E-Mail-Adresse ein Avatar-Bild zuzuordnen. Das Verfahren ist unter [2] beschrieben. Ein sehr ähnliches Beispiel hat der Autor bereits in einem früheren Linux-Magazin in der Sprache PHP umgesetzt [3]. Unter Java ist Junit [4] die Referenz in Sachen Unit-Testing. Wer die folgenden Schritte selbst durchführen möchte, installiert also das Paket in der Linux-Distribution seiner Wahl. Unter Ubuntu liefert das Paket »junit4« das Testwerkzeug.

Der Entwickler sollte an dieser Stelle erst einmal das grundlegende Setup prüfen. Zu diesem Zweck schreibt er einen ersten Test in die Datei »GravatarTest.java« (Listing 1). Stimmt alles, kompiliert der Java-Compiler den Testfall, der sich anschließend fehlerfrei ausführen lässt. Der folgende Befehl kompiliert den Test in der Java-Quelldatei zu Bytecode:

Listing 1

Der erste Test

01 import junit.framework.TestCase;
02
03 public class GravatarTest extends TestCase {
04     public void testTrue() {
05         assertTrue(true);
06     }
07 }
javac -cp /usr/share/java/junit4.jar:.GravatarTest.java

Danach sollte sich eine Datei »GravatarTest.class« im Verzeichnis befinden. Der nächste Befehl startet Junits »TestRunner« (»org.junit.runner.JUnitCore« ) mit »GravatarTest« als Testfall:

java -cp /usr/share/java/junit4.jar:.org.junit.runner.JUnitCore GravatarTest

Der einzige definierte Test (»public void testTrue« ) prüft mit »assertTrue(true)« nur, ob »true« auch wirklich wahr ist. Läuft der Test wie in Abbildung 1 ab, funktioniert die Junit-Installation wie erwartet.

Abbildung 1: Der erste Test ist erfolgreich, bestätigt aber lediglich die korrekte Installation von Junit.

In beiden Befehlszeilen legt die Option »-cp« die Pfade fest, in denen Java-Klassen zu finden sind. Dieser Klassenpfad nimmt an, dass das Jar-Archiv für Junit unter »/usr/share/java/junit4.jar« installiert ist. Jeder Ort, an dem benötigte Bibliotheken liegen, muss hinter »-cp« angegeben sein, auch das aktuelle Verzeichnis, kurz ».« .

Listing 2 erweitert die einzelne Prüfung zu einer Testsuite, die mehrere Tests aufnimmt. In der Praxis würde der Programmierer langsamer vorgehen und nur einen oder zwei Tests hinzufügen, dann den passenden Code schreiben, weitere Tests hinzufügen und so weiter. Bei Skriptsprachen ließe sich eine solche Testsuite schon ausführen.

Listing 2

Testsuite

01 import junit.framework.TestCase;
02
03 public class GravatarTest extends TestCase {
04
05     public void testAddressesOne()
06     {
07         Gravatar g = new Gravatar();
08         assertEquals("0c17bf66e649070167701d2d3cd71711", g.getId("test@example.org"));
09     }
10
11     public void testAddressesTwo()
12     {
13         Gravatar g = new Gravatar();
14         assertEquals("ae46d8cbbb834a85db7287f8342d0c42", g.getId("x@example.org"));
15     }
16
17     public void testIgnoreCase()
18     {
19         Gravatar g = new Gravatar();
20         assertEquals(
21     "55502f40dc8b7c769880b10874abc9d0",
22             g.getId("Test@EXAMPLE.com")
23         );
24     }
25
26     public void testTrimming()
27     {
28         Gravatar g = new Gravatar();
29         assertEquals(
30 "55502f40dc8b7c769880b10874abc9d0",
31             g.getId(" Test@Example.com ")
32         );
33     }
34
35     public void testAvatarUrl()
36     {
37         Gravatar g = new Gravatar();
38         assertEquals(
39             "http://www.gravatar.com/avatar/0c17bf66e649070167701d2d3cd71711",
40             g.getAvatarUrl(" Test@Example.orG ")
41         );
42     }
43 }

Java ist etwas anspruchsvoller: Ohne eine Klasse »Gravatar« weigert sich der Compiler, die Suite in Bytecode zu konvertieren. Schließlich verwendet die Testsuite diese Klasse und ruft die Funktionen »getId()« sowie »getAvatarUrl()« auf. So muss der Entwickler die Klasse in der Datei »Gravatar.java« zumindest mit ein bisschen Code ausstatten (Listing 3).

Listing 3

Gravatar.java

01 public class Gravatar {
02     public String getId(String mail) {
03         return "";
04     }
05
06     public String getAvatarUrl(String mail) {
07         return "";
08     }
09 }

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 6 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • PHP Unit

    Unit-Tests sorgen für funktionierende und wartbare Software. Dieser Artikel zeigt PHP-Entwicklern, wie sie mit dem Tool PHP Unit den Einstieg in die testgetriebene Entwicklung finden.

  • Kleiner Helfer, ganz groß

    Ant ist das Make für Java-Projekte, kann aber viel mehr: Wer Sonderwünsche hat, kann Ant beliebig erweitern und neue Tasks mit eigenen Java-Klassen verbinden. Wie das geht, zeigt dieser Coffee-Shop. Bernhard Bablok

  • Aus Fehlern klug

    Normalerweise bekämpfen Entwickler Programmfehler. Forscher aus Saarbrücken bauen jedoch sogar absichtlich Fehler in Quelltexte ein. So schätzen sie ab, wie gut Testumgebungen arbeiten.

  • Aufmerksamer Beobachter

    Will ein Entwickler seine Software mit automatisierten Tests prüfen, muss er komplexe Randbedingungen wiederholbar machen. Dabei helfen ihm Mock-Objekte, die das Verhalten von Produktionscode simulieren, ob es sich nun um ein Netzwerk oder eine Datenbankanbindung handelt.

  • Von Java zu Ajax

    Das Google Web Toolkit ermöglicht die Entwicklung aufwändiger Webanwendungen in Java und generiert daraus automatisch Ajax-Applikationen. Im Hosted-Modus wird die Suche nach Fehlern zum Kinderspiel.

comments powered by Disqus

Ausgabe 10/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.