Kategorien
Praxissemester Studium

Unit Testing

In der Softwareentwicklung gibt es, wie in jeder Ingenieursdisziplin, ein Vorgehensmodell wie komplexe Software am Besten erstellt werden sollte. Diese Planung trennt die einzelnen Schritte der Entwicklung in Teilprobleme auf, die dann weniger komplex und somit leichter zu beherrschen sind.

In der Softwareentwicklung gibt es derer fünf:

  1. Planung
  2. Analyse
  3. Design (Entwurf)
  4. Implementierung
  5. Validation und Verifikation

Ich werde hier nur auf den fünften Teil eingehen, für die ersten Teile empfehle ich jetzt nur einfach spontan mal UMLet.
Was genau bedeutet eigentlich Validation und wie grenzt man es zur Verifikation ab? In der Informatik bedeutet Validierung die Überprüfung ob ein System den Anforderungen (Aus dem 1. Teil „Planung“) entspricht. Dies muss dann natürlich auch noch dokumentiert werden. Dies könnte man auch ohne Weiteres für die Verifikation sagen, aber die beiden Wörter lassen sich am Besten mit den beiden Sätzen abgrenzen:

Validierung:

Bauen wir das richtige Produkt?

Verifikation:

Bauen wir das Produkt richtig?

Es ist also durchaus möglich ein Produkt zu verifizieren das überhaupt keinen Nutzen für den Kunden hat.

Diese beiden Hauptwörter werden mittels Test umgesetzt, wobei sich diese Tests nochmals in vier Unterkategorien unterteilen lassen. Die Einteilung passiert hier anhand der Systemstruktur:

  1. Modultest (auch Unit-Test oder Komponententest genannt)
  2. Integrationstest
  3. Subsystemtest
  4. Systemtest

Der Modultest dient der Verifikation von einzelnen Modulen, wie z.B. Klassen. Meist werden diese mittels Debuginformationen im Logfile oder direkt auf der Konsole auf Korrektheit überprüft, dies ist aber meist sehr mühsam und lässt sich nicht automatisieren. Besonders ekelhaft wird es dann wenn man auf Systemcall-Ebene runtergeht (stracen) und dort versucht die Ursache des Fehlers aufzuspüren. Die Debugausgaben blähen auch den Code auf und man (also der Programmieren) muss dann immer erst den „wichtigen“ Programmcode vom „unwichtigen“ trennen (bezogen auf die Funktionalität). Ändert man nun am Code etwas („Moment, das fix ich gschwind“), so hat man meist das eine Problem dadurch behoben das man ein anderes erzeugt hat. Wenn dieses offensichtlich ist, dann ist das kein Problem, wenn man aber Seiteneffekte kreiert die sich erst hintenrum offenbaren, so hat man sich selbst ins Knie geschossen.

Hier setzen die Unit-Tests an. Dazu werden gewisse Funktionen auf bestimmte Ein- und Ausgabewerte getestet (entweder per White- oder Blackbox-Test) und diese dann auf Korrektheit überprüft. Besonders interessant sind hierbei die Grenzwerte des Definitionsbereichs, so sollte bei einer Funktion die 20 durch einen per Parameter übergebene Zahl teilt auf die Null aufpassen, da diese natürlich gesondert behandelt werden muss. Diese Tests können dann dem Programmieren helfen seine „schnell, schnell“-Änderungen zu überprüfen, da er ja einfach nur auf einen Knopf drücken muss, die automatisierten Tests den Code testen und der Programmieren sofort weiss ob er eventuell Seiteneffekte kreiert hat. Man muss aber erwähnen dass das Erstellen von Tests nicht die 100%ige Fehlerfreiheit garantiert, es garantiert nur das die getesteten Funktion sich so verhalten wie sie sollten.

Ein bekanntes Framework zum Testen ist JUnit, dieses bietet sogar eine GUI die einem klipp und klar mittels ROT oder GRÜN anzeigt ob die Tests funktioniert haben, oder auch nicht.