Aus Linux-Magazin 12/2021

Der Testprozess und seine Verfahren in der Übersicht

© Prudencio Alvarez / 123RF.com

Im Schnitt beansprucht das Testen ein Viertel bis fast die Hälfte des Entwicklungsaufwands von Software. Dieser Artikel will dabei helfen, das Testen zu optimieren, geeignete Verfahren auszusuchen und Testfälle systematisch und strukturiert zu wählen.

Wer testet, möchte zwei Ziele erreichen: Er will nachweisen, dass die Software den Anforderungen entspricht, also funktioniert, und er will Fehler finden, bevor sie im Betrieb zu Problemen führen. Beides ist gleich wichtig. Das Testen besteht häufig darin, die Software (oder deren Teile) probeweise auszuführen. Dabei lässt sich fast nie jeder denkbare Testfall durchspielen. Umso mehr kommt es darauf an, die Testszenarien klug und systematisch so zu wählen, dass sie möglichst viele Situationen des praktischen Betriebs abdecken. Herumprobieren führt hier nicht weiter.

Der Sinn und Zweck eines Testverfahrens besteht darin, Testfälle zu entwerfen. Es gibt sowohl statische Verfahren, bei denen man das Testobjekt begutachtet und statisch analysiert, aber nicht ausführt, als auch dynamische Verfahren, bei denen man das Testobjekt mit Testdaten versieht und ausführt. Eine zweite Unterscheidung unterteilt die Verfahren danach, ob entweder die Spezifikation des Testobjekts beim Erstellen der Testfälle als Ausgangspunkt dient – dann spricht man von anforderungsbasierten Verfahren –, oder ob man beim Entwickeln der Testfälle bei der Struktur des zu testenden Programms beginnt. Solche Verfahren heißen strukturbasiert.

Dynamische Testverfahren

Die dynamischen Testverfahren lassen sich weiter unterteilen. Im einfachsten Fall definiert man Wertebereiche für die Ein- und Ausgabeparameter, sogenannte Äqiuvalenzklassen. Hier kommt es auf ein systematisches Vorgehen an, um dem Vergessen von Werten vorzubeugen, die vielleicht außerhalb des Definitionsbereichs liegen, aber auftreten können. Zunächst legt man diese Definitionsbereiche fest und unterteilt sie dann weiter so in Klassen, dass zu erwarten ist, dass sich die Software für alle Werte einer Klasse gleich (äquivalent) verhält.

Ein Beispiel wäre eine Rabattaktion, bei der bei einem Warenwert von mehr als 25 Euro ein Rabatt von 15 Prozent gewährt wird, während bei einem Wert von über 150 Euro der Käufer einen Rabatt von 25 Prozent erhalten soll. Das führt zu den Äquivalenzklassen aus den ersten drei Zeilen der Tabelle “Äquivalenzklassen und Testfälle”.

Klasse

ÄK1

ÄK2

ÄK3

Warenwert (Euro)

0 <= x <= 25

25 < x <= 150

150 < x

Rabatt (Prozent)

0

15

25

Testfall

TF1

TF2

TF3

Eingabewert (Euro)

22,50

30,00

200,00

erwartetes Ergebnis (Euro)

22,50

25,50

150,00

Nun lassen sich für einzelne Repräsentanten dieser Klassen jeweils konkrete Testfälle ableiten, für die man jeweils errechnet, welcher Endpreis sich ergibt. Nach der Testausführung vergleicht man den errechneten Wert mit dem vom Programm gelieferten Ergebnis, um zu prüfen, ob ein Fehler vorliegt oder die Berechnung korrekt erfolgte. Für die drei Äquivalenzklassen aus unserem Beispiel ergeben sich für die Repräsentanten die Ergebnisse aus den letzten drei Zeilen der Tabelle “Äquivalenzklassen und Testfälle”.

Zusätzlich gilt es jedoch, Fehleingaben zu berücksichtigen, die außerhalb des Definitionsbereichs der Eingabegrößen liegen. In unserem Beispiel beträfe das etwa negative Beträge oder exorbitant hohe Summen, die der Verkäufer nicht mehr rabattieren will. Solche Werte drücken sich in einer ungültigen Äquivalenzklasse (uÄK) oder in einer Präzisierung einer bestehenden Klasse aus (siehe Tabelle “Ungültige Aquivalenzklassen”).

Klasse

Warenwert (Euro)

Aktion

uÄK1

x < 0

Fehlermeldung

uÄK2

15000 < x <= max.

Fehlermeldung

Beim Festlegen der Testfälle erweist es sich als vorteilhaft, nicht irgendwelche Werte auszuwählen, sondern Grenzwerte, bei deren Überschreiten sich das Verhalten des Programms ändern muss. In unserem Beispiel könnten das die Eingaben »150,00« und »150,01« sein.

Kombinationen

Sind mehrere Eingabeparameter im Spiel, kommt es darauf an, systematisch alle ihre Kombinationsmöglichkeiten zu bedenken. Das gelingt am besten mithilfe einer Entscheidungstabelle.

Stellen Sie sich beispielsweise vor, ein Geschäft gäbe Kundenkarten an Stammkunden aus, deren Inhaber einen Rabatt von 7 Prozent auf alle Waren erhalten. Um den Verkauf direkt nach Öffnung (8 Uhr) anzukurbeln, gewährt der Anbieter in den ersten beiden Verkaufsstunden einen Rabatt von 5 Prozent. Beide Rabatte lassen sich kombinieren. Alle Kunden, die vor 10 Uhr einkaufen, erhalten zusätzlich ein kleines Werbegeschenk. Daraus ergibt sich die Tabelle “Rabattbedingungen”, die im oberen Bereich alle Kombinationsmöglichkeiten der Parameter und im unteren Bereich alle daraus abzuleitenden Aktionen enthält.

Kundenkarte

ja

ja

nein

nein

8 bis 10 Uhr

ja

nein

ja

nein

Rabatt

5 Prozent

X

7 Prozent

X

12 Prozent

X

Aktion

Werbegeschenk

X

X

Je mehr Parameter es gibt, desto größer und unübersichtlicher fallen allerdings auch die Tabellen aus. Dann greift man besser zu grafischen Verfahren wie der Klassifikationsbaummethode, für die es ebenfalls Werkzeuge gibt, etwa das frei verfügbare Testona Light [1].

Auch das kombinatorische Testen bietet hier eine Alternative. Die Kernidee dahinter: Man berücksichtigt nicht alle möglichen Kombinationen über alle Parameter, sondern nur Kombinationen zwischen zwei, drei oder mehreren Parametern, diese dann aber vollständig. Kombiniert man jeweils zwei Parameter vollständig miteinander, spricht man von paarweisem Testen. Ziel des paarweisen Testens ist das Entdecken aller Fehler, die auf der Interaktion zweier Parameter beruhen.

Zustände

Ein anderer Ansatz beim Testen konzentriert sich auf Zustände von Testobjekten, die ineinander übergehen. Im obigen Beispiel aus dem Handel beginnt ein neuer Kunde beispielsweise zunächst als gewöhnlicher Kunde. Kauft er dann häufiger ein, avanciert er zum Stammkunden – ein neuer Zustand. Übersteigt sein Umsatz als Stammkunde ein bestimmtes Limit, steigt er zum Großkunden auf.

Die Übergänge zwischen diesen Zuständen sollen auch in umgekehrter Reihenfolge möglich sein. In beiden Richtungen darf aber kein Zustand übersprungen werden. Ein normaler Kunde kann also nicht zum Großkunden aufsteigen, ohne vorher Stammkunde gewesen zu sein, und kein Großkunde kann direkt zum normalen Kunden degradiert werden. Jeder der Zustände erlaubt aber eine Kündigung der Geschäftsbeziehung, der ehemalige Kunde landet dann in einem Endzustand.

Dieser Mechanismus lässt sich einfach mit einem gerichteten Graphen darstellen, dessen Knoten die Zustände und dessen Kanten die Übergänge bilden (Abbildung 1). Um aus dem Graphen Testfälle abzuleiten, läuft man in Gedanken alle möglichen Pfade ab. Um keine endlosen Pfade mit Wiederholungen von Zuständen zu erhalten, beendet man das Aufsammeln der Zustände, wenn der Pfad einen Zustand bereits enthält oder der Endzustand erreicht ist.

Abbildung 1: Aus einem solchen Zustandsdiagramm lassen sich die Zust&auml;nde und die &Uuml;berg&auml;nge ersehen, die es zu testen gilt.

Abbildung 1: Aus einem solchen Zustandsdiagramm lassen sich die Zustände und die Übergänge ersehen, die es zu testen gilt.

Damit ergeben sich die zulässigen Pfade aus der Tabelle “Zustandspfade”. Sie erfassen alle Zustände und Übergänge des Graphen in mindestens einem Testfall. Hinzu kommen zwei nicht im Graphen vorhandene, verbotene Pfade, die zu einer Fehlermeldung führen müssen. Aus den Abfolgen lassen sich nun entsprechende Testfälle ableiten.

Zustand

Pfad

zulässige Pfade

A1

Anfangszustand -> Kunde -> Endzustand

A2

Anfangszustand -> Kunde -> Stammkunde -> Kunde

A3

Anfangszustand -> Kunde -> Stammkunde -> Endzustand

A4

Anfangszustand -> Kunde -> Stammkunde -> Großkunde -> Stammkunde

A5

Anfangszustand -> Kunde -> Stammkunde -> Großkunde -> Endzustand

verbotene Pfade

A6

Anfangszustand -> Kunde -> Großkunde

A7

Anfangszustand -> Kunde -> Stammkunde -> Großkunde -> Kunde

Daneben gibt es noch eine Reihe weiterer Testverfahren wie Syntaxtests, Szenariotests, Ursache-Wirkungs-Tests oder der Test von Use Cases. Schließlich gehört zu den dynamischen Testverfahren auch noch das sogenannte Fuzzing, bei dem man das Testobjekt mit Zufallswerten bestückt. Diese Art des Testens stellen die folgenden Artikel in diesem Schwerpunkt ausführlich vor.

Strukturtests

Eine andere große Gruppe strukturbasierter Testverfahren geht vom Programmtext aus. Dahinter steht die Grundidee, dass möglichst jede Anweisung des Programms mindestens einmal testweise ausgeführt werden soll. Das kann sich auch auf jede Entscheidung beziehen (zum Beispiel eine If-Anweisung), die es dann jeweils einmal mit dem Wert »true« und einmal mit »false« zu testen gilt. Diese Testverfahren lassen sich meist gut nachvollziehen, und es gibt zahlreiche Werkzeuge, mit denen sich auch der Überdeckungsgrad solcher Tests berechnen lässt.

Allerdings bedeutet selbst ein sehr hoher Grad an Anweisungsüberdeckung nicht, dass der Code keine Fehler mehr enthalten kann. Es erscheint deshalb ratsam, zuerst spezifikationsbasierte Verfahren einzusetzen und die Codeüberdeckung zu messen und dann Tests für jene Programmteile zu ergänzen, die bisher noch nicht getestet wurden.

Man unterscheidet vier Arten von Strukturtests. Anweisungstests lassen im Idealfall jede Anweisung mindestens einmal ablaufen. Entscheidungstests prüfen jede Entscheidung im Testobjekt mit jedem der beiden Wahrheitswerte. Bedingungstests spielen mit booleschen Operatoren verknüpfte Bedingungen mit allen Wahrheitswerten durch. Datenflusstests verfolgen den Weg zwischen der Entstehung und dem Verwenden einer Programmvariablen.

Intuition und Erfahrung

Neben der systematischen Auswahl von Testfällen kann sich auch die Intuition als gute Richtlinie beim Testen erweisen. Unter Umständen lassen sich so Fehler aufdecken, die man mit methodischen Ansätzen nicht findet. Kandidaten für solche Tests wären beispielsweise sehr kleine oder sehr große Werte oder beim Testen einer Sortierung umgekehrt vorsortierte Listen oder solche mit identischen Werten.

In diesen Kontext gehört auch das risikoorientierte Testen, das jene Programmteile besonders intensiv betrachtet, deren Versagen die größten Risiken birgt. Erfolg verspricht auch das ausführlichere Testen von Programmteilen, in denen man bereits Fehler entdeckt hat – oft treten dort weitere Schwachstellen zutage.

Der Testprozess

Mit der Konstruktion der Testfälle allein ist es freilich nicht getan. Im Vorfeld und im Nachgang fallen weitere Arbeiten an, die den Testprozess bilden – dafür gibt es mehrere Modelle. Die Tabelle “ISTQB-Testphasen” stellt als Beispiel kurz den vom ISTQB (International Software Testing Qualifications Board [2]) entwickelten Testprozess vor (Abbildung 2), dessen einzelne Aktivitäten sich zeitlich auch überlappen können.

Abbildung 2: Der ISTQB-Testprozess in der &Uuml;bersicht.

Abbildung 2: Der ISTQB-Testprozess in der Übersicht.

Phase

Aktivität

Planung

Festlegen einer Teststrategie und der benötigten Ressourcen (Personal, Zeit, Tools, etc.).

Überwachung und Steuerung

Kontrolle der Übereinstimmung mit dem Plan und gegebenenfalls Korrektur.

Analyse

Aus den Anforderungen an das Testobjekt wird abgeleitet, was es zu testen gilt.

Testentwurf

Festlegen der Testverfahren und Definition der Testumgebung.

Realisierung

Zuordnung konkreter Eingabewerte und erwarteter Ausgaben zu den Tests, Zusammenfassung zu Testsuiten.

Durchführung

Manuelle oder automatisierte Ausführung der Tests mit Protokollierung der Ergebnisse.

Abschluss

Archivierung der Testfälle und -daten sowie der Testumgebung, kritisches Auswerten des Vorgehens.

Die Teststufen

Durch die verschiedenen Abstraktionsniveaus, auf denen die Testobjekte angesiedelt sind, ergibt sich noch eine weitere Möglichkeit, Softwaretests zu klassifizieren. Meist werden vier Teststufen unterschieden.

Komponententests nehmen auf dem untersten Level die einzelnen Softewarebausteine oder Gruppen solcher Bausteine unter die Lupe. Auf dem Niveau darüber liegen Integrationstests, die die Schnittstellen zwischen den Komponentengruppen und das Zusammenspiel der Einzelteile prüfen. Ein weitere Stufe höher stehen Systemtests, die das System als Ganzes untersuchen. Auf der obersten Ebene dienen Abnahmetests als Qualitätsnachweis gegenüber dem Kunden. Um eine Fehlersuche sollte es hier nicht mehr gehen.

Auf jeder Stufe wird der oben dargestellte Testprozess durchlaufen, allerdings jedes Mal mit einer anderen Zielsetzung und anderen Testverfahren.

Fazit

Dieser Artikel erhebt keinen Anspruch auf Vollständigkeit. Etliche Aspekte mussten hier außen vor bleiben, zum Beispiel die testgetriebene Entwicklung oder die Automatisierung der Tests. Der Überblick über den Testprozess sollte aber verdeutlichen, dass Testen und Entwickeln keine Gegenpole sind, sondern sich gegenseitig bedingende und durchdringende Prozesse, die Engagement und Kreativität erfordern und so letzten Endes zu hoher Qualität der Software beitragen. (jcb/jlu)

Zusatzinformationen

Ausführliche Beschreibungen zum Testen finden Sie in einer Broschüre des Autors dieses Artikels auf der DELUG-DVD, die einem Teil dieser Auflage beiliegt, sowie in der ISO 29119 [3] und im Buch “Basiswissen Softwaretest” [4]. Entwickler sollten sich das Werk “Lean Testing für C++-Programmierer” [5] näher ansehen, von dem auch ein frei verfügbares Exzerpt [6] vorliegt. Ausführliche Informationen zum Vorgehen bei der Automatisierung von Tests finden Sie im Buch “Basiswissen Testautomatisierung” [7].

Der Autor

Prof. Dr. Andreas Spillner arbeitet seit über 40 Jahren im Bereich der Softwareentwicklung und -prüfung in Praxis und Forschung. Er ist Fellow der Gesellschaft für Informatik e.V., Gründungsmitglied des German Testing Board e.V. und Autor beziehungsweise Mitautor einer Vielzahl von Veröffentlichungen rund um das Thema Softwaretests.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 4 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben