• Keine Ergebnisse gefunden

Unterschiede zwischen Klassentest und Modultest

Im Dokument Das Praxishandbuch für den Test (Seite 175-179)

Unterschiede zwischen Klassentest und Modultest Zweck des Klassentests

6.1 Unterschiede zwischen Klassentest und Modultest

Klassen sind das objektorientierte Äquivalent zu den prozeduralen Modulen, aller-dings mit einigen signifikanten Unterschieden. Prozedurale Module sind im stren-geren Sinne Compilierungseinheiten. Der Quellcode ist eine Sourcedatei und das Compilierungsergebnis eine Objektdatei. Prozedurale Module haben in der Regel nur einen Eingang mit einer Parameterliste. Von diesem einen Eingang aus wird in das Modul verzweigt. Der Datenbereich eines prozeduralen Moduls kann sehr groß werden. Bis auf Sprachen wie PL/I und C, die lokale Daten für einzelne Prozeduren zulassen, sind die Moduldaten alle global, d.h. sie stehen allen einzelnen Prozedu-ren zur Verfügung. Die ProzeduProzedu-ren kommunizieProzedu-ren über diesen globalen Datenbe-reich miteinander bzw. tauschen Daten aus. Die Ausgaben einer Prozedur sind die Eingaben für ihre Nachfolgerprozeduren. Dies hat für den Test den Vorteil, dass der Datenzustand jederzeit kontrollierbar ist.

Da prozedurale Module sehr groß geraten können, kann auch ihre Ablauflogik ent-sprechend komplex werden. Die ausführbaren Anweisungen sind in Auswahl- und Wiederholungsstrukturen eingebettet und die Prozedurblöcke ineinander verschach-telt. Es ergeben sich daraus zahlreiche Verzweigungen und Verästelungen im Code.

Die Anzahl der Pfade vom Eingang des Moduls durch die Ablaufverzweigungen bis hin zu einem Ausgang wächst exponentiell im Verhältnis zur Anzahl Verzweigun-gen. Prozedurale Module sind deshalb durch sehr lange Pfade gekennzeichnet.

In der kommerziellen Datenverarbeitungspraxis haben prozedurale Module meis-tens eigene IO-Operationen. Sie kommunizieren mit ihrer Umgebung über Daten-schnittstellen oder direkte BenutzungsDaten-schnittstellen. Die Anzahl der aufgerufenen Untermodule hält sich gewöhnlich im Rahmen. Dafür sind die Parameterschnittstel-len zu den anderen ModuParameterschnittstel-len umso umfangreicher.

Beim konventionellen Modultest kommt es darauf an, die Schnittstellen des Moduls unter Test zu simulieren und alle Pfade des Moduls anzusteuern mit dem Ziel, alle logischen Verzweigungen zu überdecken [IEEE1008]. Um dies zu erreichen, sind bei komplexen Modulen mehrere hundert Testfälle erforderlich. Bei jedem Testfall

werden die Eingabedaten variiert, die einmal über eine Parameterschnittstelle, ein-mal über eine Dateischnittstelle oder einein-mal über eine Benutzungsschnittstelle in das Modul einfließen. Je mehr Schnittstellen ein Modul hat und je mehr Daten die Schnittstellen haben, umso schwieriger und aufwändiger wird der Modultest. Hinzu kommt die Komplexität der Ablauflogik. Je mehr Verzweigungen und je tiefer die Verschachtelungen, desto mehr Testfälle werden benötigt, um alle logischen Ver-zweigungen zu überdecken.

Der Aufwand für einen konventionellen Modultest wird also durch folgende Ele-mente bestimmt [Lig90]:

• die Anzahl Modulschnittstellen,

• die Anzahl Daten in den Schnittstellen,

• die Anzahl Verzweigungen im Modul und

• die Anzahl der Verschachtelungsstufen.

In der Praxis sind prozedurale Module oft zu groß und ihre Schnittstellen zu kom-plex, um einen ordentlichen Modultest auszuführen. Der Aufwand, die Schnittstel-len zu simulieren, ist auch mit einem Testrahmen zu hoch. Das kommt daher, dass die wenigsten Entwickler ihre Systeme im Hinblick auf die Testbarkeit der Module konzipieren. Als Ergebnis sind die Module weitgehend untestbar. Es ist nur dann sinnvoll, Module zu testen, wenn sie aus kleinem, überschaubarem Code mit be-schränkten, wohldefinierten Schnittstellen bestehen.

Klassen in objektorientierten Sprachen sind mit prozeduralen Modulen nicht gleich-zusetzen. COBOL oder PL/I Module entsprechen jeweils einer Quellcode-Datei (source member). In einigen OO-Sprachen wie z.B. C++ und Smalltalk-80 kann eine Quellcode-Datei mehrere Klassen beinhalten oder nur Teil einer Klasse sein.

Um eine Klasse zu testen, ist es erforderlich, mehrere Source-Members heranzuzie-hen bzw. einen Ausschnitt aus einer Source-Member herauszuschneiden. In solcheranzuzie-hen Fällen ist das alte 1:1-Verhältnis zwischen dem Quellcode und dem Testobjekt nicht gegeben.

Klassen können wie prozedurale Module einen „globalen“ Datenbereich (Klassen-variablen) haben, der allen Objekten gemeinsam zur Verfügung steht. Zusätzlich gibt es meist Datenbereiche, die für jede Instanz angelegt werden (Instanzvariablen) und für alle Methoden der Klasse zugreifbar sind. Das sind die eigentlichen Objekt-daten. Außerdem kann jede Methode eigene lokale Variablen haben. Jede Methode bzw. Operation hat einen eigenen Eingang mit einer eigenen Schnittstelle. Somit unterscheiden sich Klassen grundsätzlich von prozeduralen Modulen. Sie sind er-gebnisgesteuert. Nicht die Klasse als Ganzes wird aufgerufen, sondern nur Einzel-methoden. Ergo wird eine Klasse über den Aufruf ihrer Methoden getestet. Jede öffentliche Methode ist also im Gegensatz zu den Prozeduren in konventionellen Modulen von außen erreichbar (Abbildung 6.1). Private und geschützte Methoden

6.1 Unterschiede zwischen Klassentest und Modultest ________________________161

sind zwar von außen nicht ohne weiteres aufrufbar, können aber für Testzwecke wie öffentliche Methoden behandelt werden [LaNa97].

Klassen unter

Test

Destruktor OBJEKTINSTANZEN

Pre-Conditions

Post-Conditions Klassentreiber

Generator Validator

Eingangs-nachricht

Ausgangs-nachricht

Konstruktor

Abbildung 6.1 Klassentestumgebung

Objekte können, ebenso wie die Globaldatenbereiche der prozeduralen Welt, sehr groß werden, dennoch bleiben die Schnittstellen zu den Methoden in der Regel viel einfacher als die Modulschnittstellen. Die Methoden selbst sind in der Regel kleiner und von der Ablauflogik her weniger komplex. Dafür gibt es umso mehr Aufrufe fremder Methoden. Nicht selten bestehen Methoden fast ausschließlich aus Verwei-sen auf bzw. Aufrufen von Methoden z.T. fremder KlasVerwei-sen. Daraus folgt eine große Abhängigkeit zu fremden Klassen.

Durch die Vererbung entstehen weitere Abhängigkeiten. Eine Klasse, die von einer (oder sogar mehreren) anderen erbt, hat einen direkten Zugang zu allen Methoden und Attributen der anderen Klassen. Insofern gehören sie zusammen in einen Ad-ressraum. Wer die abgeleitete Klasse testet, testet die Basisklassen mit. Im Falle einer tiefen Vererbungshierarchie weitet sich der Klassentest dadurch aus zu einem Test der Klassenhierarchie. Dies widerspricht jedoch dem Sinn eines Modultests, der darauf zielt, ein isoliertes Testobjekt zu bestätigen. Um eine Klasse wie ein Modul zu testen, ist es notwendig, die Klasse sowohl von den fremden Klassen als auch von ihren Ahnenklassen zu isolieren. Wie dies zu bewerkstelligen ist, ist ein Thema für sich. Es genügt vorerst, auf diese Problematik und den Unterschied zum klassischen Modultest hinzuweisen [Bin94a].

Der Hauptunterschied zwischen prozeduralen Modulen und Klassen liegt letztend-lich darin, dass die Module größere interne Komplexität, die Klassen hingegen eine größere externe Abhängigkeit haben. Die Methoden einer Klasse sind zwar leichter

zu erreichen und ihre Schnittstellen leichter zu bedienen, aber es ist umso schwieri-ger, die Klasse getrennt von ihrer Umgebung zu testen. Die Instanzierung der Ob-jektdaten mit unterschiedlichen Zuständen kommt entscheidend dazu. Es ist daher keineswegs leichter, Klassen zu testen. Beide Testgegenstände – Klassen und pro-zedurale Module – haben ihre eigene Problematik. Es ist schwer zu sagen welche testbarer ist.

Robert Binder unterscheidet Klassen anhand von vier Arten der Zustandsabhängig-keit ([Bin96a], s. Abbildung 6.2) in

• nonmodale, Ein Zustand Ein Zustand Mehrere Zustände Mehrere Zustände Abbildung 6.2 Zustandsbasierte Klassentestarten

Nonmodale Klassen haben keine Abhängigkeiten zwischen den Methoden. Die Methoden können in jeder beliebigen Reihenfolge aufgerufen werden, ohne einan-der gegenseitig zu beeinflussen. Der Zustand einan-der Objekte hat keinen Einfluss auf das Verhalten der Methoden. Solche Klassen sind am einfachsten zu testen.

Unimodale Klassen setzen voraus, dass ihre Methoden in einer gewissen Reihen-folge ausgeführt werden. Der Zustand, der von der letzten Methodenausführung hinterlassen wird, ist immer eine Voraussetzung für die Ausführung der nächsten Methode. Der Tester muss auf diese Ausführungsfolge achten, z.B. muss das Konto

Im Dokument Das Praxishandbuch für den Test (Seite 175-179)