Dynamisches Software-Testverfahren
Testmethoden sind Methoden, die eingesetzt werden, um Testfälle zu bestimmen. Die verschiedenen Verfahren lassen sich wie folgt kategorisieren:
Funktionsorientierte Testmethoden
Funktionsorientierte Testmethoden werden zur Bestimmung von Testfällen benutzt, mit denen geprüft werden soll, inwieweit der Prüfling (auch Testling genannt) die vorgegebenen Spezifikationen erfüllt. Man spricht auch davon, dass „gegen die Spezifikationen“ getestet wird. Je nach Testling und Testart sind die Spezifikationen dabei von unterschiedlicher Art. Beim Modultest wird z.B. gegen die Modulspezifikation getestet, beim Schnittstellentest gegen die Schnittstellenspezifikation und beim Abnahmetest gegen die fachlichen Anforderungen, wie sie etwa in einem Pflichtenheft niedergelegt sind.
Äquivalenzklassenanalyse
bei der Äquivalenzklassenanalyse werden die möglichen Werte einer Eingabegröße (oder auch einer Ausgabegröße) in Klassen eingeteilt, von denen vermutet werden kann, dass Fehler, die bei der Verarbeitung eines Wertes aus dieser Klasse auftreten, auch bei allen anderen Vertretern der Klasse auftreten. Wenn andererseits ein Vertreter der Klasse korrekt verarbeitet wird, dann wird vermutet, dass auch die Eingabe aller anderen Elemente der Klasse nicht zu Fehlern führt. Insofern können die Werte einer Klasse als (in dieser Hinsicht) äquivalent zueinander angesehen werden.
Ein Beispiel, um diese recht abstrakte Beschreibung zu verdeutlichen: In der Spezifikation eines Online-Banking-Systems wird gefordert, dass nur Beträge zwischen 0 und 500 € eingegeben werden dürfen. Man kann dann vermuten, dass eine Überweisung in Höhe von 123,45 € akzeptiert und korrekt ausgeführt wird, wenn ein Test ergeben hat, dass eine Überweisung von 123,44 € korrekt durchgeführt wird. Verallgemeinert kann angenommen werden, dass alle Beträge zwischen 0,01€ und 500,00 € korrekt verarbeitet werden, wenn dies für einen beliebigen Betrag aus diesem Bereich der Fall ist. Es reicht also aus, einen beliebigen Vertreter aus dem Bereich zu testen, um einem möglichen Fehler auf die Spur zu kommen.
In gleicher Weise kann man für negative Werte und für Werte größer als 500 € argumentieren. Für Tests sollte es daher ausreichen, vier Äquivalenzklassen zu bilden:
- Werte kleiner Null
- den Wert Null
- Werte zwischen 0,01 und 500,00 €
- Werte größer als 500,00 €
und dann jeweils nur einen (beliebigen) Vertreter jeder Äquivalenzklasse in einem Testfall zu überprüfen.
Grenzwertanalyse
Die Grenzwertanalyse ist ein Spezialfall der Äquivalenzklassenanalyse. Sie ist aus der Beobachtung entstanden, dass Fehler besonders häufig an den „Rändern“ der Äquivalenzklassen auftreten. Daher werden hier nicht beliebige Werte getestet, sondern sog. Randwerte oder Grenzwerte. Im Beispiel wären dies die Werte
- -0,01 € (ungültige Eingabe)
- 0,00 € (ungültige Eingabe)
- 0,01 € (gültige Eingabe)
- 500,00 € (gültige Eingabe)
- 500,01 € (ungültige Eingabe)
Ein Nachteil der beiden Verfahren Äquivalenzklassen- und Grenzwertanalyse ist es, dass Abhängigkeiten zwischen verschiedenen Eingabewerten nicht berücksichtigt werden können. So ist es etwa bei der Prüfung einer eingegebenen Adresse nicht ausreichend, für Ortsnamen, Straßennamen und Postleitzahlen jeweils (z.B. an Hand einer Datenbank) zu prüfen, ob diese zur Klasse der gültigen Werte gehören. Sie müssen auch zusammenpassen.
Zustandsbasierte Testmethoden
Zustandsbasierte Testmethoden basieren auf Zustandsautomaten, die heute oft als UML-Diagramm dargestellt werden.
In der Beschreibung des Zustandsautomaten sind üblicherweise keine Fehlerfälle vorgesehen. Diese sind zusätzlich zu spezifizieren, indem zu jeder Kombination {Ausgangszustand; Ereignis} (auch den im Automaten nicht spezifizierten Kombinationen) der Folgezustand und die ausgelösten Aktionen angegeben werden. Diese Kombinationen können dann alle getestet werden. Einsetzbar sind zustandsbasierte Methoden außer in technischen Anwendungen auch beim Test grafischer Benutzeroberflächen und von OO-Klassen, die durch Zustandsautomaten definiert sind.
Um die Vollständigkeit der so ermittelten Testfälle zu prüfen, gibt es verschiedene Kriterien: Werden bei den Tests alle Zustände durchlaufen? Werden alle Zustandsübergänge durchlaufen? Werden alle Ereignisse, die Zustandsübergänge hervorrufen, getestet?
Ursache-Wirkungs-Analyse
Bei dieser Methode werden Ursachen und Wirkungen jeder Teilspezifikation identifiziert. Eine Ursache ist dabei eine einzelne Eingabebedingung oder eine Äquivalenzklasse von Eingabebedingungen; eine Wirkung ist eine Ausgabebedingung oder eine Systemtransformation.
Die Teilspezifikation wird in einen Boole’schen Graphen überführt, der Ursachen und Wirkungen durch logische Verknüpfungen verbindet. Anschließend wird der Graph um Abhängigkeiten auf Grund von syntaktischen Zwängen oder Umgebungsbedingungen ergänzt. Die folgenden Arten von Abhängigkeiten zwischen Ursachen werden dabei unterschieden:
- Exklusive Abhängigkeit: Die Anwesenheit einer Ursache schließt andere Ursachen aus.
- Inklusive Beziehung: Mindestens eine von mehreren Ursachen liegt vor (z.B. ist eine Ampel immer grün, gelb oder rot – oder rot und gelb zusammen. Wenn sie funktioniert und eingeschaltet ist).
- One-and-only-one-Beziehung: Es liegt genau eine von mehreren Ursachen vor (z.B. männlich oder weiblich oder Zwitter).
- Requires-Abhängigkeit: Die Anwesenheit einer Ursache ist Voraussetzung für das Vorhandensein einer anderen (z.B. Alter > 21 und Alter > 18).
- Maskierungsabhängigkeit: Eine Ursache verhindert, dass eine andere Ursache eintreten kann.
Der so entstandene Graph wird zu einer Entscheidungstabelle umgeformt. Dabei werden bestimmte Regeln angewandt, die aus einer Verknüpfung von n Ursachen n+1 Testfälle generieren (statt , wie es bei einer vollständigen Entscheidungstabelle der Fall wäre). Dabei entspricht jeder Testfall einer Spalte der Entscheidungstabelle.
Entscheidungstabellen-basierter Test
Hier werden die Testfälle auf Basis von Entscheidungstabellen ermittelt, indem Regeln spezifiziert werden, die Bedingungskombinationen mit den zugehörigen Aktionen verknüpfen. Die Methode ähnelt der Ursache-Wirkungs-Analyse.
Strukturorientierte Testmethoden
Strukturorientierte Testmethoden bestimmen Testfälle auf Basis des Softwarequellcodes.
Software-Module enthalten Daten, die verarbeitet werden, und Kontrollstrukturen, die die Verarbeitung der Daten steuern. Entsprechend unterscheidet man Tests, die auf dem Kontrollfluss basieren, und Tests, die Datenzugriffe als Grundlage haben.
Kontrollflussorientierte Tests
Diese Techniken zur Ermittlung von Testfällen basieren auf der Kontrollstruktur bzw. dem Kontrollfluss der zu testenden Software.
Anweisungsüberdeckungstest ( -Test)
Beim Anweisungsüberdeckungstest werden alle Knoten des Kontrollflussgraphen von mindestens einem Testfall abgedeckt, d.h., jede Anweisung im Quelltext wird mindestens einmal ausgeführt. Der C0-Test hat keine praktische Bedeutung, da er ein zu schwaches Kriterium für eine sinnvolle Testdurchführung darstellt.
Zweigüberdeckungstest ( -Test)
Hier werden die Testfälle so spezifiziert, dass alle Zweige (Kanten) des Kontrollflussgraphen mindestens einmal durchlaufen werden.
Auch diese Methode hat Nachteile:
Oft ist es schwierig, Programmzweige zu durchlaufen, da bestimmte Betriebssystemzustände oder schwierig zu erzeugende Datenkonstellationen erforderlich sind. Zudem werden Kombinationen von Zweigen und komplexe Bedingungen nicht angemessen berücksichtigt.
Schließlich werden Programmschleifen nicht ausreichend getestet, da ein einzelner Durchlauf durch den Schleifenkörper von abweisenden Schleifen und eine einzelne Wiederholung von nicht abweisenden Schleifen für die Zweigüberdeckung ausreichend ist.
Einfacher Bedingungsüberdeckungstest ( -Test)
Hier wird die Struktur der Entscheidungen innerhalb des Testlings für die Testfallermittlung herangezogen. Dabei wird gefordert, die Testfälle so zu bestimmen, dass die Auswertung jeder atomaren Teilentscheidung einmal den Wert wahr und einmal den Wert falsch ergibt.
Dies berücksichtigt jedoch nicht, dass Bedingungen oft aus geschachtelten logischen Verknüpfungen von Teilentscheidungen bestehen. Dadurch werden Fehlersituationen maskiert: Bei „oder“ - Verknüpfungen reicht es, wenn die erste Teilbedingung wahr ist, bei „und“ – Verknüpfungen, wenn die erste Bedingung falsch ist, um den weiteren Kontrollfluss festzulegen. Fehler in den anderen Bedingungsteilen werden nicht erkannt. Daher garantiert der einfache Bedingungsüberdeckungstest nicht einmal eine Zweigüberdeckung.
Mehrfach-Bedingungsüberdeckungstest(/-Test)
Der minimale Mehrfach-Überdeckungstest verlangt, dass neben den atomaren Teilentscheidungen und der Gesamtentscheidung auch alle zusammengesetzten Teilentscheidungen gegen wahr und falsch geprüft werden.
Der modifizierte Bedingungsüberdeckungstest verlangt darüber hinaus Testfälle, die demonstrieren, dass jede atomare Teilentscheidung den Wahrheitswert der Gesamtentscheidung unabhängig von den anderen Teilentscheidungen beeinflussen kann (Das wird etwa vom Standard RTCA DO-178B für flugkritische Software gefordert).
Der wesentliche Nachteil ist der extrem hohe Testaufwand: Bei n Teilentscheidungen ergeben sich Testfälle.
Pfad-Überdeckungstests ( -Test)
Beim Pfadüberdeckungstest werden sämtliche unterschiedlichen Pfade des Testlings in mindestens einem Testfall durchlaufen. In der Regel ist dies allerdings nicht durchführbar, da es sehr häufig unendlich viele Pfade gibt – bedingt durch Schleifen ohne feste Wiederholungszahl. Ein weiteres Problem ist die Nichtausführbarkeit eines Teils der aus dem Kontrollflussgraphen konstruierbaren Pfade. Ein Beispiel dafür: Steht im Programmcode zunächst „Wenn Bedingung A dann Zweig 1 sonst Zweig 2“ und später „Wenn Bedingung A dann Zweig 3 sonst Zweig 4“, dann können Pfade, die Zweig 1 und Zweig 4 enthalten, nicht ausgeführt werden.
Der Pfadüberdeckungstest hat daher keine praktische Bedeutung.
Datenflussorientierte Tests
Datenflussorientierte Testmethoden basieren auf dem Datenfluss, also dem Zugriff auf Variablen. Sie sind besonders geeignet für objektorientiert entwickelte Systeme.
Wegen ihrer Kompliziertheit sind die Techniken zur datenflussorientierten Testfallermittlung nur werkzeuggestützt einsetzbar. Da es aber kaum Werkzeuge gibt, haben sie zur Zeit noch keine praktische Relevanz.
Diversifizierende Testmethoden
Die Gruppe der Diversifizierenden Tests umfasst einen Menge von Testtechniken, die verschiedene Versionen einer Software gegeneinander testen. Es findet kein Vergleich zwischen den Testergebnissen und der Spezifikation , sondern ein Vergleich der Testergebnisse der verschiedenen Versionen statt. Ein Testfall gilt als erfolgreich absolviert, wenn die Ausgaben der unterschiedlichen Versionen identisch sind.. Auch wird im Gegensatz zu den Funktionsorientierten und Strukturorientierten Testmethoden kein Vollständigkeitskriterium spezifiziert. Die notwendigen Testdaten werden mittels einer der anderen Techniken, per Zufall oder Aufzeichnng einer Benutzer-Session erstellt.
Die Diversifizierender Tests umgehen die oft aufwändige Beurteilung der Testergebnisse anhand der Spezifikation. Dies birgt natüliche die Gefahr, dass ein Fehler, der in den zu vergleichenden Versionen das gleiche Ergebnis produziert, nicht erkannt wird. Aufgrund des einfachen Vergleichens lassen sich solche Tests sehr gut automatisieren.
Back to Back-Test
Beim Back to Back-Test enstehen verschiedene gegeneinander zu testende Versionen aus der n-Versionen-Programmierung, d.h. die Programmierung verschiedener Versionen einer Software, nach der gleichen Spezifikation. Die Unabhängigkeit der Programmierteams ist dabei eine Grundvorraussetzung.
Dieses Verfahren ist sehr teuer und nur bei entsprechend hohen Sicherheits-Anforderungen gerechtfertigt.
Mutationen-Test
Der Mutationen-Test ist keine Testtechnik im engeren Sinne, sondern ein Test der Leistungsfähigkeit anderer Testmethoden, sowie der verwendeten Testfälle. Die verschiedenen Versionen entstehen durch künstliches Einfügen von typischen Fehlern. Es wird dann geprüft, ob die benutzte Testmethode mit den vorhandenen Testdaten diese künstlichen Fehler findet. Wird ein Fehler nicht gefunden, so werden die Testdaten um entsprechende Testfälle erweitert. Diese Technik beruht auf der Annahme, dass ein erfahrender Programmierer meist nur noch "typische" Fehler macht.
Regressionstest
Aufgrund der mehrdeutigen Verwendung des Begriffes, ist im ein eigener Artikel gewidmet.