Die richtige Methode entscheidet über die SW-Qualität, Folge 5:

Standardisierte Tests noch in weiter Ferne

12.11.1982

Letzte Stufe vor der Implementierung von Softwareprogrammen ist der Test. Und da gibt es dann immer noch Probleme, die sich in der Wahl der geeigneten Testverfahren manifestieren. Ein weiterer wichtiger Vorgang ist das Selektieren der Testdaten, insbesondere das von falschen Daten, um das Verhalten der Module auf Fehlinformationen zu überprüfen. Es bleibt auf diesem für die Qualität eines Programmes wichtigen Sektor reichlich Raum für Diskussionen. In dieser fünften und letzten Folge des Beitrages zur Qualitätssicherung werden Testverfahren und Vorgehensweisen beschrieben die Problemlösungen vorschlagen.

Die Testmethoden und auch die Werkzeuge werden natürlich von den Entwicklern und entsprechenden Theoretikern erfunden. Aus der Sicht der Qualitätssicherung ist rein technisch nichts dagegen einzuwenden, solange einige wichtige Forderungen erfüllt werden, die vor allem den Einsatz der Methoden und Werkzeuge betreffen:

- Das Testen muß von der Entwicklung unabhängig sein. Ein Brauch, den die Entwickler nicht besonders gerne sehen, der aber theoretisch begründet ist und auch praktisch schon viele Erfolge erzielt hat. Das soll nicht heißen, daß man entsprechende Kapazität unbedingt bei der Qualitätssicherung aufbauen muß. Aber es zeichnet sich ab, daß das SW-Testen eine eigenständige Disziplin innerhalb der SW werden wird.

- Die Testprogramme müssen geeignet für Abnahmen sein. Das bedeutet, daß das, was getestet wird und die zugehörigen Ergebnisse sichtbar werden müssen.

- Abschließend eine technisch-wirtschaftliche Forderung: Die Tests müssen wie "richtige" SW behandelt werden, insbesondere also den Engineering-Verfahren unterliegen und entsprechend dokumentiert und verwaltet werden. Nur so ist gewährleistet, daß man in der Wartungsphase nicht alles noch einmal machen muß.

Code via Syntaxchecker

Der nächste Schritt nach der Fertigstellung des Entwurfs ist die Codierung. Der üblichen Praxis, den erzeugten Code gleich einmal ablaufen zu lassen (er "könnte ja schließlich gehen"), folgen wir eingedenk eines der Murphyschen Gesetze nicht: "Wenn alles so aussieht, als ob es funktioniert, hat man offensichtlich etwas übersehen."

Durchaus möglich ist es, den Code über den Syntaxchecker laufen zu lassen. Die Entfernung von Syntaxfehlern auf diese Weise sollte eine Selbstverständlichkeit sein und erfordert auch nicht viel Zeitaufwand. Es sind dies aber auch die Fehler, die nicht besonders weh tun.

Danach sollte nach heutigen Erkenntnissen unbedingt eine (manuelle) Überprüfung des Codes folgen. Zwei Methoden stehen dafür zur Verfügung: der "Code Walkthrough" oder die "Code-Inspektion". Die Vorgehensweise bei den an sich ähnlichen Verfahren unterscheidet sich darin, daß beim Walkthrough der jeweilige Entwickler anwesend ist und die Fragen gleich beantworten kann.

Letztlich ist es eine Geschmacksfrage, welche Methode man wählt. In jedem Falle dient auch hier eine Checkliste dazu, nichts Wesentliches zu vergessen. Wichtig sind:

- funktionelle Erfüllung der Moduldefinition,

- richtige Interpretation der Schnittstellen,

- Einhaltung der Codierregeln (Programmkopf, Deklarationen, Verwendung von Namen und Labels, Kommentare, Strukturregeln),

- Überprüfen der Ablauflogik

- Achten auf typische Fehler wie falsche Indizes, falsche Schleifenbedingungen, Überläufe, Bereichsüberschreitungen, Rundungsfehler, Division durch Null.

Statistisch kann man auf diese Weise bereits bis zu 60 Prozent der Fehler entdecken (was immer diese Zahl auch zu bedeuten hat).

Nach diesem QS-Akt folgt der Modultest als erster eigentlicher Testschritt. Ein Entwicklungsvorgang, der selbstverständlich auch qualitätssicherungsrelevant ist, weil dieser Schritt natürlich mit der Abnahme und Freigabe der einzelnen Module abgeschlossen werden soll.

Tests parallel zu den Programmen

Beim Modultest handelt es sich also um das Austesten der durch den strukturierten Entwurf gewonnenen Grundbausteine. Ein Problem dabei ist, daß diese Bausteine ja nicht fähig sind, selbständig abzulaufen. Der wesentliche Vorteil des Modultests ist die Möglichkeit, sehr nahe an die berühmte Fehlerfreiheit zu gelangen. Der folgende Schritt der SW-Integration soll dann davon ausgehen, funktionierende Bausteine zu haben, so daß man nur noch gleichsam die Schnittstellen überprüfen muß.

Modultests werden wie die anderen Tests parallel zu den eigentlichen Programmen entworfen. Eingangsinformation für die Tests ist einmal die Nachweisanforderung aus dem Anforderungsdokument, zum anderen der Entwurf des eigentlichen Programms. Wobei der Idealfall natürlich erreicht wäre, wenn sich beide gegenseitig beeinflussen würden, also Testbarkeitsaspekte auch im eigentlichen Entwurf Eingang finden würden.

Inzwischen gibt es auch einige allgemeine Forderungen an Tests:

- Testprogramme sollten so einfach wie möglich sein, da es ja nicht noch einmal Tests für die Tests geben kann.

- Sie sollten soweit wie möglich verallgemeinert werden. Konkret heißt das: Prinzipiell besteht ein Test aus einer Testablaufsteuerung, aus Eingabedaten, aus Referenzdaten zum Vergleich der "gemessenen" Daten und einer Testauswertung. Dies sind durchaus verallgemeinerungsfähige Eigenschaften.

- Die eigentliche (und kreative) Tätigkeit besteht in der richtigen Auswahl der Testdaten.

Eine recht vernünftige Einteilung von Testtypen ist die Einteilung in statische und dynamische Tests. Statische Tests sind die Verfahren, bei denen das Programm nicht real abläuft, sondern bestenfalls mit symbolischen Parametern.

Hierfür gibt es auch schon eine Menge von Tools. Schlagworte sind zum Beispiel die Pfadanalyse, bei der jeder mögliche Pfad überprüft werden soll. Dies ist bei einer gewissen Größe schnell nicht mehr möglich. Oder der etwas anspruchslosere kleine Bruder "Zweiganalyse", bei der nur sichergestellt wird, daß jeder Programmzweig mindestens einmal durchlaufen wird. Für die symbolische Ausführung gibt es auch Tools, die natürlich sehr sprachspezifisch sind.

Die dynamischen Tests sind eigentliche Ablauftests, zum Teil in simulierter Umgebung. Hier läßt sich besonders das "Echtzeitverhalten" überprüfen.

Eine weitere Unterscheidung liegt darin, ob man den Modul als "Black-Box" oder als "White-Box" testet. Letzteres erfordert die Anbringung von Testpunkten im Programm mit dem Vorteil besserer Lokalisierung und dem Nachteil der Verfälschung des Laufzeitverhaltens und der Tatsache, sich eine zusätzliche Fehlerquelle geschaffen zu haben.

Welche Art von Tests man nun wirklich beim Modultest durchführt, hängt natürlich zum einen von der Aufgabe des Moduls ab. Allgemeine Richtwerte hierfür existieren leider nicht (außer den erwähnten Correctness Provers als komplizierte, nachträgliche Bestätigung einer Vorgehensweise). Im Moment ist dies auch, wie so vieles in der SW-Technologie, eine Frage der Erfahrung.

Nach dem Test der Module erfolgt die Integration zu einem Gesamtsystem. Neben der nach wie vor gültigen Forderung nach Unabhängigkeit der Testaktivitäten noch ein weiterer Grundsatz: Man füge niemals mehr als jeweils einen neuen Modul hinzu. (Die alte Vorgehensweise "Mal sehen, ob alles funktioniert" ist passé.) Grund für diese Forderung ist wieder die Möglichkeit, Fehler überhaupt zu entdecken, was bei großen Komplexen ohne das Schaffen von Fixpunkten eben unmöglich ist. Für die Integration gibt es unterschiedliche Strategien mit den Exponenten: Top-down, Bottom-up.

"Stubs" unterschätzt

Dazwischen existieren noch Namen wie Inside-out, Outside-in oder Hardest-first. Welche Strategie die beste ist, hängt auch hier vom Problem und Geschmack der einzelnen Beteiligten ab.

Einen Nachteil der Top-down-Methode möchten wir aber hier vermerken, weil er uns aus wirtschaftlichen Gründen gravierend erscheint: Durch die fehlenden Programmteile der unteren Hierarchiestufen müssen teilweise aufwendige Simulatoren erzeugt werden sogenannte "Stubs", deren Komplexität häufig unterschätzt wird. Für einen guten Test müssen sie nämlich fast alle Daten wie der Modul erzeugen und darüber hinaus noch möglichst falsche Daten, um das Verhalten des Bausteins auf Fehlerinformationen zu überprüfen.

Die beim Modultest erwähnte Toolgruppe kann in den meisten Fällen auch hier zur Anwendung kommen.

Die SW-Integration ist natürlich in erster Linie kein Qualitätssicherungsprozeß. Trotzdem wird heute empfohlen, als eine QS-Maßnahme, die Tätigkeit zu beobachten und tagebuchartig zu dokumentieren, was erfahrungsgemäß sehr wertvoll für eine Schwachstellenanalyse sein kann. Nach der erfolgreichen SW-Integration ist der Gesamttestlauf und eine abschließende Code-Inspektion (der Code hat sich normalerweise durch den Test verändert) der letzte Verifikationsschritt.

Das nächste Problem ist die Validierung.

Aufgabe der Validierung ist es nachzuweisen, daß die SW die ursprünglichen Anforderungen und die Qualitätsmerkmale erfüllt. Das heißt, neben den bisherigen Testprogrammen, die die Funktion oder auch das Fehlverhalten überprüfen, kommen jetzt noch neue Forderungen. Welche Arten von Tests kommen hier in Frage?

- Test, ob die direkten Anforderungen erfüllt sind. Diese müssen nicht identisch mit den Funktionen sein. Besonders betont werden muß hier die Qualität in bezug auf die Benutzerschnittstelle. Im Prinzip ist also die Beantwortung der Frage, ob das, was der Benutzer sich vorgestellt hat, die SW erfüllt und ob das auch in einer dem Benutzer angepaßten Weise geschieht.

- Test, ob die geforderten maximalen Volumina erfüllt werden. Dazu muß man die entsprechenden großen Datenmengen erzeugen und eingeben. Eine weitere Variante wäre der sogenannte Streß-Test, insbesondere relevant bei Multi-user-Systemen.

- Sicherheitstest, wobei die Sicherheit gegen die Fehlbedienung, aber auch der Datenschutz gemeint sind.

- Performance-Test also die Überprüfung, ob eventuell geforderte Reaktionszeiten in jeder Situation eingehalten werden.

- Speicherbelegungstest

- Kompatibilitätstests bei Zusammenspiel mit anderer SW

- Zuverlässigkeitstest, der zum Beispiel auch durch einen längeren Dauerbetrieb mit entsprechender Fehleraufzeichnung geführt werden kann (wenn die Forderungen nicht zu hoch sind).

- Robustheitstest, also die Überprüfung, wie sich das System bei aufgetretenen Fehlern (von außen wie innen) verhält.

Diese Auflistung hat sehr viel mit den Qualitätsmerkmalen zu tun. Was im einzelnen durchzuführen ist, sollte bereits in der Anforderung festgelegt sein. Dies ist deshalb erforderlich, weil die meisten dieser Tests sehr aufwendig sind. Außerdem sind wir noch weit davon entfernt, für diese Aufgaben generelle Tools zur Verfügung zu haben.

"Software-Wissenschaft" im Aufbruch

Die so durchgeführte Validierung dient dann auch gleichzeitig als "Acceptance-Test" für den Auftraggeber. So sollte es von Anfang an vereinbart sein.

Was dann folgt, ist ein Probebetrieb (Field-test) oder gleich die Installation mit dem leidigen Problem von Wartung vor allem während der Garantiezeit. Aber mit einer Methodik, wie sie hier angedeutet ist, ist das unter Umständen gar nicht mehr so schlimm.

Genaugenommen befindet sich die "Wissenschaft von der Software" erst im Aufbruch. Bei dem explosionsartigen Zuwachs der Bedeutung der SW werden die Anstrengungen zwangsläufig verstärkt werden. Vielleicht ist SW-Engineering und -QS dann auch bald eine objektive, mathematische Wissenschaft. Im Augenblick ähnelt sie mehr anderen Fakultäten. Diskussionen über Testmethoden erinnern derzeit noch fatal an die Streitgespräche von Psychologiestudenten über Traumdeutung. Bei der Traumdeutung wollen wir hoffen, daß es so bleibt, für die SW-Entwicklung ist der Zustand auf Dauer unerträglich. Ende

* Friedrich Haugg ist als Diplom-Mathematiker bei MBB in Ottobrunn in der SW-Qualitätsicherung tätig.