Unit Test – mach’s mit!

5 Kommentare

Es ist jetzt etwas mehr elf Jahre her, da habe ich in einem Projekt für das damalige Internet Startup Censio meinen ersten Unit Test geschrieben. Kent Beck hatte gerade sein eXtreme Programming Buch veröffentlich und gemeinsam mit Erich Gamma in den Schweizer Bergen JUnit programmiert. Das Projekt bei Censio war stressig, der Internet Boom war auf seinem Höhepunkt und das ganze Entwickler Team arbeitete praktisch rund um die Uhr. Durch den Stress schlichen sich bei mir viele Fehler ein und JUnit erschien mir eine Möglichkeit dieses Problem in den Griff zu bekommen und so war es auch! Seit dem bin ich Unit Test infiziert und habe keinen Code mehr ohne Unit Tests geschrieben.

Trotzdem sehe ich noch viele Projekte die Code ohne Tests entwickeln. Das ist für mich nicht nachvollziehbar und deshalb möchte ich mit diesem Blog eine Serie starten, die zeigen soll warum Unit Tests so nützlich sind und wie man als Entwickler richtig testet.

Mich erinnerte das ein wenig an die neue „Gib Aids keine Chance“ Kampagne: Mach’s mit. Auch meine Message an alle Entwickler: Mach’s mit Unit Tests!

Was sind Unit Tests?

Unit Tests werden auch Modultests genannt, weil sie ein konkretes Software Modul auf Programmierfehler überprüfen. Typischerweise testet ein Unit Test eine Klasse oder eine Schnittstelle. Die Module werde dabei isoliert von einander getestet, d.h. ohne die Interaktion/Integration mit anderen Modulen.  Dadurch werden die Tests sehr robust und können schnell ausgeführt werden. Ein fehlgeschlagener Test bedeutet zudem, dass ein Fehler in dem getesteten Modul gefunden wurde – als Entwickler muss man daher nicht lange nach dem fehlerhaften Code suchen.

Warum Unit Tests?

Unit Tests sind ein wichtiger Bestandteil für agile (und nicht agile) Software Entwicklung:

  • Kurze Entwicklungszyklen mit lauffähiger Software am Ende sind fester Bestandteil jeder agilen Methode. Nur wenn der Code automatisiert getestet wird, ist er robust genug, damit nachfolgende Iteration darauf aufbauen können. Ohne diese Tests wird die Entwicklungsgeschwindigkeit sinken und das Team wird sich mehr mit Bugfixing beschäftigen als mit neuen Funktionen.
  • Ohne Unit Tests funktioniert kein Continuous Integration!
  • Ohne Unit Tests kann man kein Refactoring machen!
  • Ohne Unit Tests funktioniert Collective Code Ownership nicht!
  • Ohne Unit Tests ist ein emergentes Design schwierig – gerade ein Test First Ansatz führt zu besserem Design und besserem Code.
  • Unit Tests sind zudem die beste Dokumentation die ich kenne. Neue Teammitglieder können somit schneller und einfacher eingearbeitet werden. Andere Teammitglieder haben es einfach den Vertrag (contract) einer Klasse oder eines Service zu verstehen.

Vorurteile gegenüber Unit Tests

Trotzdem: Immer noch gibt es viele Projekte ohne Unit Tests oder ohne funktionierende Unit Tests (maven.test.skip=true ist ein weit verbreiteter Parameter und der Beweis dafür). Die Argumente sind immer gleich:

  • Keine Zeit für Unit Tests.
  • Kein Budget für Unit Tests.
  • Der Kunde wollte keine Unit Tests bzw. hat diese nicht eingefordert.
  • Unit Tests würden für die Anwendung oder die eingesetzten Technologien nicht funktionieren.
  • Man würde die Unit Test erst am Ende des Projekts schreiben.

Fehlendes Knowhow

Meine Erfahrung ist, dass diese Argumente nur vorgeschoben sind. Der wahre Grund ist, dass das Team nicht weiß wie man seinen Code richtig testet. Denn auch wenn die Frameworks wie JUnit oder TestNG einfach aussehen, so ist Unit testen alles andere als einfach. Testgetriebene Entwicklung (TDD) ist noch schwieriger – es ist eine ganz andere Philosophie Anwendungen zu entwickeln. Man muss dazu wissen, wie man Testfälle konzipiert, Testdaten erstellt und verwaltet, Mock Objekte erzeugt, Testabdeckung misst, Testfälle refactored und mit verschiedensten Technologien und Frameworks wie Java EE oder Spring beim Testen umgeht. Oft wird man mehr Testcode erzeugen als funktionalen Code und doch gibt es nur selten Konventionen für Testcode und noch weniger Test Design Patterns.

Deshalb werde ich an Hand eines konkreten Beispiels Schritt für Schritt in einzelnen Blog Einträgen zeigen, wie man aus meiner Sicht richtig Unit testet und dabei unterschiedliche Frameworks, Konventionen und Test Design Patterns vorstellen. Hoffe auf viel Feedback von meinen Kollegen, sowie Unit Test Freunden und Gegnern, so dass am Ende viel mehr Entwickler sagen werden: Ich mach’s mit…Unit Tests!

Teil 1: JUnit – Der erster Testfall

Autor

Mirko Novakovic

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Artikel von Mirko Novakovic

Konferenzen

APM Mythen Jäger entlarvt

Performance

Debunking the APM myth busters

Kommentare

  • Hallo Mirko,
    ich bin mal wirklich gespannt auf Deine Serie. In einem größeren Projekt haben wir Unit-Tests ein wenig zweckentfremdet: Die Anwendung war in 3-Schichten konzipiert und wir haben alle Einstiege in die 2. Schicht (Businessschicht) mit Unit-Tests geprüft. Dabei werden natürlich meistens mehrere Module auf einmal getestet. Hat sich aber als sehr effektiv erwiesen und der Umfang des Testcodes ist deutlich kleiner als in der „klassischen“ Variante.

  • Juli 29, 2011 von Frank Hinkel

    Hallo Mirko,
    ich finde alle Erfahrungswerte zum Test First Ansatz sind Gold wert. Ich kann alle Pro und Contra Punkte blind unterschreiben. Mir fehlt ein sehr wichtiger Aspekt bei den Gründen, die uns davon abhalten zu testen bzw. die uns das Leben so schwer machen.

    Und zwar folgender:
    1. Ich muss meinen Business Code auch so schreiben, dass er testbar ist.
    2. Der Code von anderen, den ich Verwende muss testbar geschrieben sein.

    Aus meiner Perspektive war es oftmals vergleichsweise leichter die Testfälle an sich zu schreiben und dabei entsprechende Mocking Methoden und Tools einzusetzen, die alles um meine Unit herum synthetisieren; als fachlichen Code so zu programmieren, der testbar ist bzw. fremden Code zu verwenden, der es nicht ist.

    Punkt eins kann ich beeinflussen wenn ich weiß wie ich programmieren muss um überhaupt Testfälle schreiben zu können. Aber letzteren – also Fremdcode – leider oftmals nicht.
    Wie teste ich also Software, bei der ich überall wie wild „new“ Operatoren im Code finde oder durch tiefe Vererbungshierarchien tonnenweise Fachlogik weitergereicht wird und sich kaum wegmocken lässt?

  • Juli 29, 2011 von Mirko Novakovic

    Hallo Frank,

    danke für Deine Frage. Aus meiner Sicht hast Du genau der Punkt getroffen, der TDD, aber auch andere Praktiken wie CI so schwer in der Umsetzung machen:

    Auch wenn es auf den ersten Blick aussieht, als ob es sich bei TDD, CI & Co primär um Technologien, Methoden und Tools handelt, so ist es in Wirklichkeit auch eine Philosophie die dahinter steckt mit einer Änderung der Art und Weise wie man entwickelt.

    Um konkret auf Deinen Punkt einzugehen, was man macht, wenn man es mit Code zu tun hat, der nicht testbar ist, gibt es hier zwei Praktiken dafür, die aus dem eXtremePorgramming kommen:

    1. Collective Code Ownership: http://www.extremeprogramming.org/rules/collective.html

    2. Refactoring http://www.extremeprogramming.org/rules/refactor.html

    Im Klartext heißt das: Schnapp Dir den Code und mach Ihn testbar :-) Am Besten noch im Pairprogramming mit dem ursprünglichen Entwickler. Das Ergebnis ist, dass sich das Design der Anwendung verbessert und sie insbesondere testbarer wird. D.h. für Deinen Auftraggeber/Kunden: Mittelfristig sinken die Wartungskosten und es gibt weniger Fehler – zudem sind Änderungen einfacher umzusetzen.

    Ich weiß, dass das nicht einfach ist in einer Organisation umzusetzen, aber man muss in kleinen Schritten daran arbeiten.

    Mirko

  • August 2, 2011 von Mirko Novakovic

    Hallo Jörg,

    denke, dass solche „Integrations“-Unit-Tests auch sinnvoll sind und helfen Fehler zu vermeiden.

    Es gibt aber auch Nachteile, die ich schon selber in Projekten erlebt habe:

    – Das Ausführen der Tests dauert oft sehr lange, weil DB etc. involviert sind. Dadurch werden die Test weniger oft ausgeführt.

    – Die Entwicklung der Testfälle wird komplexer und hat mehr Abhängigkeiten (z.B. Datenbank mit bestimmten Daten, TX Management, etc. etc). Das kann dazu führen, dass man weniger Tests erzeugt bzw. Tests „abgeschaltet“.

    Wenn es aber für Euch gut funktioniert hat, dann spricht nichts dagegen es so zu machen. Hauptsache man macht’t mit :-)

    Grüße
    Mirko

  • Hallo Mirko,
    vielen Dank für den informativen und hilfreichen Artikel.
    Eine Frage hätte ich noch an dich. Zwar wo liegt der Unterschied zwischen statischem und dynamischem Testen?

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *