Testverfahren erleichtern den Entwicklungsprozess

Produktiver Arbeiten

 

Einleitung:

Heutzutage wird Software mit einer Vielzahl von Programmierfehlern (Bugs) ausgeliefert. Der Endanwender fungiert dann Recht schnell als Betatester. Dabei kann mittels verschiedener Testverfahren der Entwicklungsprozess vereinfacht werden. Dies lässt sich mit Hilfe von so genannten Testing-Tools fast automatisieren.

 

Fließtext:

Bei der heutigen Software wird davon ausgegangen, dass diese funktionstüchtig und fehlerfrei ist. Die Realität sieht anders aus. Das fällt meist nicht auf, da der Anwender nur zirka 15% der Funktionalität eines Produktes nutzt und somit keine Fehler bemerken. In anderen Branchen wie der Automobilindustrie wäre so eine Situation undenkbar. Die möglichen Folgen und entsprechenden Maßnahmen wird das Problembewusstsein langfristig bei denEntwicklern und ihrer Vorgesetzten erhöhen. Obwohl viele dieser Fehler zwar seit langem bekannt sind, ist die Vermeidung dieser Fehler trotzdem weitaus schwieriger, als es auf den ersten Blick scheint. Bei immer kürzer werdenden Entwicklungszyklen und ständig steigender Komplexität der äußeren Rahmenbedingungen muss mit dem zur Verfügung stehenden Budget in möglichst kurzer Zeit qualitativ hochwertige Software entwickelt werden, die außerdem noch entsprechenden Konkurrenzprodukten überlegen ist. Die Kosten für die Beseitigung von Produktmängeln stellen in der Regel direkt entgangenen Gewinn dar. Der Entwicklungsprozess ist deshalb unter vertretbarem Aufwand so zu gestalten, dass Mängel gar nicht erst auftreten. Jedoch Sind komplexe Programme bei der Programmierung schwer zu durchschauen und können Fehler enthalten. Mittels eines Testing-Tools besteht aber die Möglichkeit, die Fehlerquellen bestmöglich einzugrenzen.

 

Test im Softwareentwicklungsprozess

Mit einem Software Inspektionstest versucht ein Team die Fehler und sonstige Probleme innerhalb eines Programms zu finden. Generell gehört das Testen (Testing) von Software zum Entwicklungsprozess dazu. Jedoch sehen die meisten Softwareentwickler diesen Aufgabenprozess als langwierig und nebensächlich an. Es sind Testfälle zu schreiben, die Ausnahmefälle sind zu definieren und welche Ausgabeergebnisse schließlich erwartet werden. Sobald der Veröffentlichungstermin naht, werden automatisch immer weniger Tests gefahren, um das Produkt zum richtigen Zeitpunkt auszuliefern zu können. Das ist aber ein Trugschluss,  denn je weniger Tests gemacht werden, desto größer werden die Schwierigkeiten in den späteren Projektphasen. Sobald man die Tests durchführt, beschleunigen diese konsequent den Entwicklungsprozess, da nicht mehr so viel Zeit in die Fehlerbehebung fließen muss. Die Gesamtzeit eines Projektes nimmt somit also ab. Gleichzeitig wird dem Softwareentwickler durch die Kombination von Codierung mit Tests, die Softwareentwicklung leichter gemacht. Ein Softwaretester ist am erfolgreichsten, wenn er den aktuelle Stand der Probleme im Programm kennt und weiß, wo er ansetzen muss. So findet der Softwaretester bereits 80% der Fehler in der Vorbereitungsphase. In der Haupttestphase müssen dann nur noch die restlichen 20% Fehler gefunden werden. Dies zeigt, dass eine entsprechende Vorbereitung ein Garant für den Erfolg ist. Der Arbeitsaufwand erhöht sich in späteren Phasen prozentual, wenn keine kontinuierlichen Test gefahren werden. Bei den meisten Projekten ist aus Zeitmangel kaum eine ausführliche Testphase möglich. Umso wichtiger ist ein Tool, dass den Testprozess vereinfacht.

 

Kostensparen

Solche Tests führen zu einer Verbesserung der Softwarequalität und steigert die Produktivität des Projektteams. Viele Unternehmen haben festgestellt, dass eine Produktivitätssteigerung von 25 – 35% nicht unüblich sind. Die Abbildung#1 zeigt,

auf welche Phasen eines Softwareprojektes sich diese Einsparungen verteilen. In jeder Phase fällt die Überarbeitungsarbeit an, welche nötig ist, weil man nicht absolut fehlerfrei arbeiten kann. Wenn zum Beispiel im Intergrationstest ein Fehler gefunden wird, kann es sein, dass dieser sich als Entwurfsfehler herausstellt. In diesem Fall sind die Entwurfsdokumente entsprechend anzupassen und bestimmte Funktionen müssen neu programmiert werden. Erst wenn das passiert ist, kann der Integrationstest weiter fortgeführt werden. Es ist also wichtig, dass man am Anfang sehr sorgfältig arbeitet, um nicht später alles neu entwickeln zu müssen.

 

Die Vorteile von Tests

Grundsätzlich existieren drei Ebene die den Entwicklungsprozess mittels Tests beeinflussen:

1. Der Entwickler braucht nicht mehr so viel Zeit in die Entwicklung zu stecken, da die Debuggingvorgänge zurückgehen.

2. Die Programmfehler werden frühzeitiger gefunden und somit können sich keine weiteren Fehler einschleichen.

3. Der Debugging Vorgang fällt leichter, da die Fehlerquellen eingegrenzt sind.

 

Als Fazit lässt sich immer sagen:

„Ein Code mit vielen Fehlern, benötigt wesentlich mehr Zeit für dessen Behebung, als ein Code, wo jeder Bug frühzeitig behoben wurde.“

Ein weiterer positiver Sachverhalt ist, die sichere Wiederverwendung von Codeeinheiten. Ein so genannter Unit-Test erlaubt das Austesten und die Überprüfung jeder einzelnen Komponente. Ist die Komponente überprüft, kann diese wieder verwendet werden, da sie funktioniert. Kommt es dann zu einem Fehler, kann man sicher sein, dass dieser vom Codefragment außerhalb der Komponente stammt. Das Testen von Softwareeinheiten sichert die Basis für wieder verwendbare Komponenten. Ebenso erlauben solche Test, dass bei Codeänderungen die Auswirkung sofort sichtbar ist. Die Arbeitsweise des Codes wird für den Entwickler transparent. Sobald die Testfälle fertig definiert sind, kann die Prüfung beginnen. Muss nach der Prüfung etwas geändert werden, ist eine erneute Prüfung notwendig. Es ist sofort ersichtlich, wenn Fehler sich einschleichen.

 

Die verschiedenen Testverfahren

Die Überprüfung bzw. die verschiedenen Testverfahren haben das Ziel, die Korrektheit des Programms zu wiederlegen. Dazu gibt es die dynamischen Testverfahren, wie das

Strukturtestverfahren (White-Box-Test) und das funktionale Testverfahren (Black Box-Test). Beim dynamischen Testverfahren wird das auszuführende Programm mit konkreten Eingabewerten versehen und damit ausgeführt. Das Programm wird so in einer realen Umgebung geprüft. Beim Strukturtestverfahren wird geprüft, ob der Kontroll- und der Datenfluss des Programms wie geplant funktionieren. Beim Testen der Klassen wird der Objektzustand mitberucksichtigt und alle Methoden werden dabei getestet. Mit einer Vielzahl von Testfällen wird dies überprüft. Dies zeigt ihre Beziehungen zueinander. Jedoch handelt es sich hierbei nur um Stichproben. Für den White-Box-Test ist ein hoher Aufwand nötig und besitzt eine große Komplexität. Es wird zusätzlich eine automatische Unterstützung benötigt. Beim funktionalen Testverfahren wird hingegen nur die Funktionalität eines bestimmten Teils des Programms geprüft. Es wird auf Basis der Schnittstellen einer Klasse getestet ohne die Internas zu beachten. Dabei werden Testeingaben ausgewählt, die an der Klasse(n) ausprobiert werden sollen um bestimmte Ausgabedaten zu erhalten. Fallen unerwartete Ausgabedaten an, sind folglich die Programmfehler entsprechend auszubessern. Der Softwaretester erhält jedoch keine Informationen darüber, ob es Zustandsänderungen durch Methodenaufrufe gab oder ob die Methoden eine Wirkung auf andere Objekte haben. Die ausschließliche Betrachtung der Ausgabedaten sind nicht ausreichend und hilft dem Softwaretester nicht viel weiter. Er erfährt nur, ob eine Funktion funktioniert oder eben nicht. Die Schwachstellen des Black Box-Tests können durch White-Box-Test umgangen werden.

Zusätzlich gibt es noch die statischen Testverfahren. Dabei wird das Programm nicht ausgeführt, sondern nur der Quellcode analysiert, um etwaige Fehler zu finden. Hierbei spricht man von: Walkthroughs oder Codeinspektion. Beim statischen Testverfahren wird geprüft, ob die Darstellungskonventionen eingehalten wurden und die Namensgebung und Kommentierung der Dokumentation entsprechen. Zusätzlich wird die Komplexität geprüft, wie viel Schnittstellen existieren und wie viel Klassen kommen zum Einsatz. Dann werden noch die Kontrollstrukturen geprüft, ob überhaupt alles erreichbar ist. Bei der Codeinspektion wird von einem Team (Moderator, Protokollant, Inspektor)

das gesamte Programm sequentiell durchgegangen. Der Quellcode wird Schritt für Schritt durchgegangen, um die Problemstellen ausfindig zu machen. Dieses Vorgehen hat einen hohen Nutzen, da so durschnittlich 60% ausfindig gemacht werden. Das Verfahren ist sehr zeitaufwendig und verursacht gleichermaßen hohe Kosten. Alle Testverfahren dienen zum Bestimmen und dem Beseitigen von Fehlern, die bei Testläufen aufgetreten sind. Das Ergebnis des Tests ist stark abhängig davon, ob die Testdaten gut waren und auch Sonderfälle mitabgedeckt wurden. Dies kann man nicht automatisieren. Nur ein Softwaretester kann diese Testdaten erstellen. Somit ist es enorm wichtig, das der Softwaretester den konkreten Aufbau des Programms kennt.

 

Ein guter Algorithmus

Wie kann jedoch ein möglichst korrekter Algorithmus erzielt werden? Prinzipell sollte er sauber definiert sein und bestimmen, welche Eingaben und welche Ausgaben dieser erzeugt. Dann kommt die partielle Korrektheit: Auf alle erwarteten Eingaben muss der Algorithmus das gewünschte Ergebnis liefern. Somit erfüllt er die Spezifikation. Auf ungültigen Eingaben signalisiert der Algorithmus durch Abbruch der Routine oder Setzen eines dafür reservierten Ergebnisses. Hierbei wurde die Spezifikation verletzt.

 

Das Entwicklungstool: JTest

Mit Hilfe des Produkts „JTest“ lässt sich der Testprozess vereinfachen. Dessen Installation ist schnell erledigt. Es kann von der Website www.parasoft.com heruntergeladen werden. Dort ist eine Testversion zu finden. Nach einer Registrierung kann man die Trial-Version herunterladen. Um das Produkt ausführen zu können, ist ein Registrierungsschlüssel nötig, welcher per eMail zugesandt wird. Die Installation erfolgt wie üblich über ein Setup-Programm. Mittels dessen wird es auf das jeweilige System aufgespielt. Jetzt steht es zum Aufruf bereit.

 

Der Ablauf eines Tests

Um einen ersten Test durchzuführen, wählt man einfach eine Klasse aus und drückt die grüne Schaltfläche. Sobald JTest mit dem Testvorgang fertig ist, wird das Ergebnis innerhalb einer Baumansicht dargestellt. Es zeigt eventuell statische Analyse Fehler oder nicht abgefangene Laufzeitfehler (Runtime Exceptions) an. Das Produkt „JTest“ erlaubt drei Arten von Tests auf Klassenebene durchzuführen. Dies ist die so genannte statische Analyse–Test, der White-Box–Test und der Black–Box–Test. JTest führt automatisch immer einen Analyse–Test und White-Box–Test durch. Bei der statischen Analyse lassen sich eine Reihe von Regeln vorgeben, was (überhaupt) zusätzlich getestet werden soll. So lassen sich Projektstandards berücksichtigen, welche eingehalten werden sollen. Wenn im Projekt standardmäßig alle privaten Variablen mit der Kennung „prv“ beginnen, lässt sich dies als Regel setzen. JTest markiert dann automatisch alle Variablen, die nicht dieser Regel entsprechen. Solche Regeln können natürlich ziemlich komplex sein. Die meisten sind als Standard etabliert und haben sich in Projekten bewährt. JTest erlaubt ganz gezielt solche Regeln zu definieren, wozu es den grafischen Rule-Builder bereitstellt. Diese Regelformulierungen werden stets schrittweise umgesetzt. Bei komplexen Regeln muss schließlich die Logik stimmen. Es braucht aber trotzdem einiges an Erfahrung um an die Grenzen des Tools zu stoßen. Mittels statischer Analyse lassen sich Codierungstandards prima einhalten. Früher musste dazu der Code umständlich begutachtet und angepasst werden.

 

Das Strukturtestverfahren (White-Box-Test)

Mit Hilfe des White-Box–Test versucht JTest die Codelogik zu Fall zu bringen, indem es unerwartete Eingaben am Code ausprobiert. Dabei wird keinerlei Funktionalität getestet. Es wird allein das Objektverhalten geprüft, ob unerwartete Eingaben akzeptiert werden und wie darauf dann reagiert wird. Hierzu ein Beispiel wie so ein Test aussehen kann. Es wird bei einer Objektmethode der Parameter NULL als Testfall übergeben. Während beim Hauptobjekt noch alles korrekt läuft, reagieren meist die anderen Objekte nicht mehr wie erwartet. Mittels JTest lassen sich solche schwachen Codestellen sehr gut offenlegen bzw. identifizieren. Das Verfahren legt offen, an welche kritischen Fälle der Entwickler nicht mehr gedacht hat diese zu implementieren. Bei Test erfährt man Recht schnell eine Überraschung, woran es im Detail noch mangelt. Aber es ist ja kein Problem, dies noch zu implementieren.

 

Das Funktionale Testverfahren (Black Box-Test)

Die Ausführugn eines Black Box – Test ist wesentlich schwerer auszuführen. Als Grundlage werden Benutzereingaben benötigt, um die Funktionalität überprüfen zu können. Dies erlaubt zu prüfen, ob der Code genau das macht, was er (in bestimmten Situationen) soll. JTest ermöglicht es zwei Arten von Tests durchzuführen. In der ersten Variante werden konkrete Argumente spezifiziert, welche auf ein Objekt angewendet werden. Die zweite Variante erlaubt das Erstellen so genannter Testfälle (Test Cases), welche sich auf Klassenbasis beziehen. Hierbei handelt es sich um einen wesentlich komplexeren Testvorgang. Bei der Methodenmanipulation wird eine Methode mit einem bestimmten Argument aufgerufen. Solche Argumenttypen lassen sich auf verschiedene Arten definieren. Am einfachsten geschieht dies über die Baumstrukturansicht. Dieser Baum listet alle Methoden und ihre Argumente auf. Um ein Argument anzulegen, nutzt man die rechte Maustaste. Schnell wird man feststellen, dass immer wieder die gleichen Konstanten verwendet werden. Zusätzlich will man auch NON-Primitiven nutzen können. Dazu stellt JTest ein Repository bereit, wo man die bereits definierten Konstanten und Methoden vorfindet. Diese Testmethode ist jedoch nur auf einzelne Klassen geeignet.

 

Komplere Tests

Jedoch gibt es Situationen, wo ein Test um einiges komplexer ausfällt. Hierzu lässt sich das folgende Beispiel anführen. Der Test der Klasse „Stack“ ist so ein Fall. Der Tester will hierbei wissen, ob die Elemente in der richtigen Reihenfolge wieder vom Stapel (Stack) heruntergenommen werden. Um dies prüfen zu können, müssen zuerst Daten innerhalb des Stacks abgelegt werden. Anschließend kann die Funktionalität der Methode push() geprüft werden. Die Methodenmanipulation würde hier nicht ausreichen, da dort nur eine Methode aufgerufen werden kann. Sobald mehrere Methodenaufrufe nötig sind, ist eine Testklasse zu schreiben. JTest erleichtert diesen Testprozess, indem es ein robustes Test Framework bereitstellt. Die Tests lassen sich unabhängig zum Tool erstellen. Steht die Testbasis kann JTest aufgerufen werden. Die aktuellen Tooleinstellungen lassen sich innerhalb einer Datei sichern, sodass der Test jederzeit wiederholt werden kann. Dabei wird das Ergebnis des letzten Tests automatisch mit gesichert. So lässt es sich in einer History zurückverfolgen, zu welchen Ergebnis die einzelnen Tests gekommen sind.

 

Fazit:

JTest ist ein sehr leistungsfähiges Produkt. Es verfügt über eine Projektansicht und generiert externen Code (Stubs) und arbeitet im Batchmodus. In der Projektansicht lassen sich mehrere Klassen zur gleichen Zeit testen. Die Testumgebung lässt sich auch sichern, wenn später fortgefahren werden soll. Prinzipiell ist eine Benutzeroberfläche sehr nützlich. Da jedoch die meisten Projekte erst nachts getestet werden, stellt JTest hierzu einen Batchmodus bereit. Zusätzlich generiert JTest automatisch so genannte Stubs für externe Ressourcen (Corba, EJB, Datenbank). Der große Vorteil des Tools ist, dass ein Test möglich ist, ohne das die externen Ressourcen zuerst vorliegen müssen. Dessen Generierung lässt sich individuell konfigurieren. Gegenüber anderen Tools automatisiert JTest alles und stellt zugleich eine komplette Testumgebung bereit. Zugleich lassen sich Tests wiederholt ausführen, ohne manuell eingreifen zu müssen. Es lassen sich Rückschlüsse ziehen, wo der Code noch Schwächen hat. Ein Teststand lässt sich jederzeit sichern. JTest ist für die Plattformen Windows 2000/NT, Solaris und Linux verfügbar. Jedoch verügt das Produkt auch über Schwächen. Aber kein Programm kann perfekt sein. Alle Konfigurationsarbeiten geschehen innerhalb eines einzelnen Dialogs. Dieser stellt die Optionen zur Konfiguration innerhalb einer Baumansicht dar. Darüber lassen sich Regeln, Tests und andere Optionen betrachten. Der Einsatz von Menüs wäre sicherlich intuitiver gewesen. Es existieren so viele Einträge, dass es schwerfällt, dass zu finden, was man gerade braucht. Das Produkt ist hilfreich, aber sehr umfangreich, sodass man sich zuerst eingearbeiten haben muss. Die Schwierigkeiten sind aber zu meistern, da JTest über eine gute Dokumentation und etliche Tuturials verfügt. Also testen Sie Ihren Code!!!

 

Web-Sites:

Systematisches Testen in der Software Entwicklung: http://www.fbe.hs-bremen.de/spillner/systtest/sld001.htm

Vortrag: “Software Qualität und Testverfahren”: http://www.informatik.hu-berlin.de/~hanft/publ_doc/FoSemJuni98_sw_qualitaet_test/votrag_folien.htm

Software-Test

http://www.dpunkt.de/leseproben/3-88229-183-4/Gliederung.pdf

Entwurf, Implementierung und Test: http://www.fh-wedel.de/~mo/lectures/se.html

 

#Bildunterschriften:#

Bild1.tif: Nach der Analyse zeigt Jtest an, wieviele Fehler gefunden werden konnten.

Bild2.tif: Mittels Test Cases kann eine Klasse gezielt durchgetestet werden.

Bild3.tif: Die Regeln die beim Test eingehalten werden sollen, lassen sich gezielt innerhalb einer Baumstruktur setzen.

Bild4.tif:

Das Ergebnis eines Tests kann man sich auch als Report ausgeben lassen.

Bild5.tif: Man findet auch ein umfangreiches Tutorial vor.

Bild6.tif: Das Diagramm zeigt, wieviel Fehler im Lauf des Projektes anfallen und wiviele behoben werden.

Bild7.tif:

Im Diagramm werden die relativen Kosten zu Fehlerbeseitigung aufgeführt.