Softwarequalität Fünf Prinzipien dynamischer Softwaretests

Autor / Redakteur: Richard H. Kölbl* / Martina Hafner

Dynamische Softwaretests haben zum Ziel, ein Programm oder Teile daraus kontrolliert ablaufen zu lassen und dadurch Fehlverhalten aufzuspüren. Es versteht sich von selbst, dass die ungeheure Vielfalt von Softwareprogrammen mit zahlreichen Testvariationen einhergeht. Dennoch gibt es eine Reihe von Prinzipien, die für nahezu alle Tests anwendbar sind.

Anbieter zum Thema

Grundvoraussetzung ist, dass der Code testbar ist. Wesentlich bedingen dies die Kontrollierbarkeit, Beobachtbarkeit und Ausführbarkeit des Codes. Kontrollierbar bedeutet, dass die zur Testausführung notwendigen Parameter übergeben werden können und der Programmablauf von außen so gesteuert werden kann, dass der Test bei möglichst geringem Aufwand hohe Testaussagen liefert.

Um solche Aussagen überhaupt erhalten zu können, muss eine gewisse Beobachtbarkeit gegeben sein. Was bei Benutzeroberflächen auf dem PC relativ einfach ist, kann bei komplexer Embedded-Software auf einem Stück Hardware schwierig bis nahezu unmöglich sein. Vielfach können nur zu Debugzwecken temporär eingebaute Zwischenausgaben von Variablenbelegungen an interessanten Codestellen oder das Beobachten von Datenverkehr an Schnittstellen und Ähnliches entscheidende Hinweise geben.

Oft stellt aber die Ausführbarkeit des Codes ein entscheidendes Hindernis dar, vor allem bei komplexen Systemarchitekturen. Sie sind in der Regel modular aufgebaut. Das heißt, sie setzen sich aus funktionellen Einheiten zusammen, die untereinander nur so weit vernetzt sind bzw. sein sollten, wie unbedingt notwendig. Das ermöglicht es, ein Modul aus seinem Verbund herauszuschneiden und die Abhängigkeit von seiner Umgebung durch Codestücke zu befriedigen, die die Anwesenheit seiner sonstigen Nachbarn vortäuschen.

Eine solche Umgebung nennt man Testrahmen. Der Testrahmen übernimmt die Ausführung und Steuerung des Programms, versorgt das Prüfmodul mit Testdaten, zeichnet die Testergebnisse auf und erstellt einen Testreport. Idealerweise wird der Test-rahmen so konzipiert, dass möglichst viele Module des Gesamtsystems zum Test eingebaut werden können.

1. Testen Sie systematisch und gezielt

Der Testprozess sollte in jedem Fall systematisch und im Voraus geplant werden. Unsystematisches Testen ist in Einzelfällen sinnvoll, beispielsweise vom Entwickler als Ersttest durchgeführt vor der Übergabe seines Werks an den Tester zur systematischen Prüfung. Es sollte aber die Ausnahme bleiben.

Die zentrale Herausforderung besteht darin, Testfälle zu gewinnen und auszuwählen. Ein Testfall ist ein einmaliger, auch teilweiser Programmlauf mit einer bestimmten Parametrisierung und einer möglichst eindeutigen Ausgabe. Einem Testfall sollte eine möglichst schmal gehaltene Frage an das System zu Grunde liegen: Wie verhält es sich, wenn ein bestimmter Parameter geändert wird. Mit schmal ist gemeint: So wenig Eingaben wie möglich sollten variiert werden, um ein Fehlverhalten möglichst eindeutig einer veränderten Eingabe zuordnen zu können. In der Praxis ist es aber nicht immer durchführbar, nur einen Parameter zu verändern.

Um Testfälle zu gewinnen sollten zwei Umstände besonders beachtet werden: In welcher Phase befindet sich das Projekt und welche Anforderungen wurden dafür definiert? In Anlehnung an das V-Modell [IEEE/IEC 12207] können drei wesentliche Entwicklungsphasen unterschieden werden mit je einer eigenen Testcharakteristik:

  • Erstellung der Komponenten (Module) -> Komponenten- oder Modultest.
  • Integration der Komponenten zu Teil/Gesamtsystem -> Integrationstest.
  • Erstellung des Gesamtsystems -> Systemtest.

In der Praxis gibt es naturgemäß eine sehr hohe Variabilität und fließende Übergänge.

2.) Gewinnen Sie die Testfälle aus den Anforderungen

Grundsätzlich sollte zur Testfallgewinnung von den Anforderungen ausgegangen werden, die für die jeweilige Ebene definiert wurden. Dies ist insbesondere während der Integration von Komponenten zu einem Teilsystem nicht immer der Fall; das System „soll einfach laufen“. Hier ist am meisten die Fantasie und Erfahrung des Testers gefragt. Hingegen sollten die Anforderungen auf der Komponentenebene klar definiert sein, sodass sie von den Testfällen systematisch abgeprüft werden können. Ebenso klar müssen die Anforderungen an das Gesamtsystem vorliegen und beim Systemtest als funktionierend nachgewiesen werden.

3) Beschränken Sie den Testaufwand auf ein durchführbares Maß

Ein vollständiger Systemtest ist in der Praxis nicht nur aus organisatorischen, sondern schon aus rein formalen Gründen nicht möglich. Wollte man nur auf Modulebene beispielsweise alle möglichen zulässigen Eingaben prüfen, schnellt die Zahl der Testfälle nicht selten in die Tausende bis Hunderttausende hoch. Unter Berücksichtigung aller unzulässigen Eingaben und Kombinationen kann sich die Anzahl ins Unmäßige potenzieren. Das wird als Testfallexplosion bezeichnet.

Um diese einzudämmen, wird in der Regel die Äquivalenzklassenmethode eingesetzt, um die Menge der Testvektoren zu ermitteln, von denen jeder eine unterschiedliche Reaktion beim Testobjekt hervorruft. Unter Testvektor versteht man die Summe aller Eingabe- und Umgebungsparameter, die ein System zur Durchführung eines Testfalles benötigt. Alle Testvektoren, deren Eingabe voraussichtlich dieselbe Reaktion hervorruft, werden in eine gemeinsame Äquivalenzklasse zusammengefaßt. Testvektoren, deren Eingabe eine davon verschiedene Reaktion bedingt, definieren eine weitere Äquivalenzklasse und so weiter. Sind alle Klassen festgelegt, kann der Test mit jeweils einem Repräsentanten aus jeder Klasse durchgeführt werden.

Als minimaler Testumfang ist diese Vorgehensweise vertretbar. Die Erfahrung des Testleiters spielt ebenso eine Rolle wie der verfügbare Zeit- und Budgetrahmen, ob zur Sicherheit mehrere Testvektoren einer Klasse getestet werden. Es stellt sich immer wieder heraus, dass es durch unglückliche Kombinationen von Softwaredefekten Ausreißer in den Klassen gibt, die oft nur zufällig gefunden werden. Dem kann auch dadurch Rechnung getragen werden, dass bei Wiederholung der Tests die repräsentativen Testvektoren variiert werden. Dadurch begegnet man gleichzeitig der Gefahr, dass ein System durch Wiederholung der stets gleichen Testsi-tuationen bei gleichzeitigem Debugging gegen das Testen quasi immun wird. Ein Phänomen, das als Pestizidparadox bekannt ist.

4) Testen Sie Grenzwertbereiche auf saubere Definitionen

Eine weitere Methode ist die Grenzwertanalyse. Hierbei werden die zulässigen Grenzbereiche von Parametern von beiden Seiten dicht am Grenzwert und möglichst exakt auf ihm selbst abgetestet. Dieses vorwiegend auf Modultest-ebene eingesetzte Verfahren findet Schwachstellen der Grenzwertdefinitionen in Spezifikationen. Nicht immer ist bei einer Angabe wie „größer 3“ klar, ob dabei wirklich >3 oder eigentlich ≥3 gefordert war. Ein guter Tester sollte darauf ganz besonders achten.

Schließlich sind statistische Tests mit einer statistisch relevanten Anzahl von zufälligen Eingaben in einem automatisierten Testverfahren durchaus sinnvoll. Wenn die zulässigen Wertebereiche sehr groß sind oder um die Stabilität eines Systems zu testen, werden solche Tests eingesetzt. Es sollte dabei sichergestellt werden, dass der Test von seinem Ansatz her eine statistisch vertretbare Aussage liefern kann.

5) Denken Sie an Systemzustände, die nicht in den Spezifikationen stehen

Alle bisher erwähnten Testverfahren gehen von den Spezifikationen aus. Der Tester sollte aber auch im Auge haben, dass besonders bei Fehlbedienungen und -zuständen eines Systems naturgemäß nicht immer alle Fälle in der Spezifikation berücksichtigt worden sind. Zudem ergibt sich mit wachsendem Testfortschritt meist eine Erweiterung oder zumindest eine Verlagerung der Testschwerpunkte.

Von den Tests wird erwartet, dass sie einerseits möglichst vollständig und effektiv sind, andererseits aber ökonomisch. Mit diesem Zwiespalt hat der Tester ständig zu kämpfen. Er muss damit fertig werden, dass beim Testen grundsätzlich gerne personell und materiell gespart wird und der Rücklauf zu den Entwicklern bei gefundenen Fehlern mit anschließender Wiedervorlage beim Tester vom Aufwand her oft unterschätzt wird.

Testpläne sind vielfach Kompromisse, eingeklemmt zwischen Anspruch und Budget und müssen aus all diesen Gründen eine gewisse Flexibilität aufweisen. Von Entwicklern wird das Testen nicht selten als uninteressant und nicht herausfordernd genug abgetan. Die vorausgegangene Übersicht, die nur eine sehr knappe sein konnte, sollte aber gezeigt haben: Testen ist eine Aufgabe, die tiefes technisches Verständnis, Verantwortungsbewusstsein und Flexibilität fordert. Sie lebt von dem Bewusstsein, dass Qualität in ein Produkt nicht hineingetestet, sondern nur hineingeplant werden kann und dass Testen niemals vollständig sein kann, obwohl es implizit erwartet wird.

(ID:241960)