Systematische Testfallgenerierung für den Black-Box-Test


Diplomarbeit, 2005

125 Seiten, Note: Sehr gut


Leseprobe

Inhaltsverzeichnis

1 Einleitung

2 Grundlagen
2.1 Qualität
2.1.1 Produktqualität
2.1.2 Prozessqualität
2.2 Prozessmodelle
2.3 Testen
2.4 Testverfahren
2.4.1 Statische Verfahren
2.4.2 Dynamische Verfahren

3 Im Werkzeug umgesetzte Testverfahren
3.1 Äquivalenzklassenanalyse
3.1.1 Bestimmen der Äquivalenzklassen
3.1.2 Definition der Testfälle
3.1.3 Beispiel
3.2 Category-Partition Methode
3.2.1 Unabhängige Partitionen
3.2.2 Abhängige Partitionen
3.2.3 Beispiel
3.3 Grenzwertanalyse
3.4 Unit-Tests

4 Benutzerhandbuch
4.1 Einführung in TestIt
4.1.1 Systemvoraussetzungen
4.1.2 Installation
4.2 Funktionsweise
4.2.1 Erzeugen der Testdaten
4.2.2 Erzeugen des Testablaufs
4.3 Benutzeroberfläche
4.3.1 Menü- und Symbolleiste
4.3.2 Statusleiste
4.3.3 Standardschaltflächen für Dialoge
4.3.4 Datei-Dialog
4.3.5 Klassenansicht
4.3.6 Mitteilungen-Fenster
4.3.7 Ausgabe-Fenster
4.3.8 Eigenschaften-Fenster
4.3.9 Auflistungs-Editor
4.3.10 Bedingungen-Editor
4.3.11 Quelltext-Editor
4.3.12 Navigator
4.3.13 Programm-Einstellungen
4.4 Verwenden von TestIt
4.4.1 Erstellen der Metainformationen
4.4.2 Quelltext-Vorlagen erstellen
4.4.3 Testfälle vervollständigen
4.4.4 Ausführen der Tests
4.4.5 Beispiele
4.4.6 Tipps und Tricks
4.5 Erweitern von TestIt
4.5.1 Erstellen von Plugins
4.6 Referenz
4.6.1 Fehlermeldungen
4.6.2 Quelltext-Marken
4.6.3 Tastenkürzel

5 Implementierung von TestIt

5.1 Model-View-Controller
5.2 Datenmodell
5.2.1 PropertyGrid
5.2.2 Kulturinformationen
5.2.3 Laufzeit-Typinformationen
5.2.4 Persistenz
5.2.5 Testspezifikation
5.3 Testfallerzeugung
5.4 Plattformunabhängigkeit
5.5 Projekte
5.5.1 AssemblyParser
5.5.2 ComponentModel
5.5.3 Controls
5.5.4 MetaInfo
5.5.5 SharpParser
5.5.6 TestIt
5.5.7 TestSpecParser
5.5.8 Util
5.6 Laufzeitstatistik

6 Ähnliche Projekte
6.1 Condition-Table-Methode
6.2 Cause-Effect-Graphing
6.3 Revealing Subdomains
6.4 Partition Analysis

7 Ausblick
7.1 Verbesserung der Bedienung
7.2 Weiterentwicklung
7.2.1 Testing by Contract
7.2.2 Object Constraint Language

8 Zusammenfassung

9 Literaturverzeichnis

10 Glossar

11 Index

Kurzfassung

Testen ist die Grundlage, um qualitativ hochwertige Software zu er­stel­len. Obwohl das Testen im Softwareentwicklungsprozess einen hohen Stellenwert ein­neh­men sollte, wird es dennoch oft vernachlässigt. Vermutlich ein Grund dafür, dass Testen mit hohem Arbeitsaufwand ver­bun­den ist und hauptsächlich per Hand durch­ge­führt werden muss.

In dieser Arbeit wird eine systematische Methode zur automatischen Testfallgenerierung für den Black-Box-Test vorgestellt. Das für die Umsetzung der Methode implementierte Werk­zeug verknüpft Unit-Tests mit Äquivalenzklassen- und Grenzwert­analyse. Durch den Ge­brauch von Quelltext-Vorlagen ist das Programm völlig unabhängig vom eingesetzten Unit-Testing-Frame­work und der verwendeten Programmiersprache. Darüber hinaus können die Test­fälle auch als textuelle Beschreibung viel abstrakter formuliert werden.

Zur Einführung in die Thematik des Testens wird zuerst der Begriff Qualität definiert. Darauf auf­bauend werden Prozessmodelle zur Softwareentwicklung vorgestellt und gezeigt wie sie Ein­fluss auf die Softwarequalität nehmen. Ein Überblick über Testen im Allgemeinen und Test­verfahren im Besonderen ermöglichen die Einordnung der vorgestellten Testmethoden in einem breiteren Kontext. Im Anschluss daran werden die im Werkzeug umgesetzten Test­me­thoden ausführlich be­schrieben. Das Benutzerhandbuch und ausgewählte Problemstellungen der Implementierung er­möglichen einen tieferen Einblick in das Werkzeug selbst. Ein Aus­blick auf mögliche Verbesserungen und Weiterentwicklungen runden diese Arbeit ab.

Abstract

Testing is the basis for developing high quality software. Although testing should be held dear, it is still neglected very often. This is presumably because of the amount of work involved and it has to be done manually.

In this thesis a systematic approach for generating black-box tests automatically will be intro­duced. The implemented tool for realizing the approach combines unit testing, equivalence partitioning and boundary analysis. By making use of source code templates the program is entirely not constrained by the appointed unit-testing framework and the used programming language. Furthermore the test cases may also be expressed as a textual description in a more abstract way.

For the introduction of the topic, the term quality will be defined firstly. Based on this, soft­ware development methodologies are presented and it is shown how they influence software quality. A survey of testing in general and testing approaches in particular allows the classi­fi­cation of the presented testing approaches within a wider context. Following that the im­ple­mented testing approaches are described in detail. The user manual and selected problems of im­plementation provide a deeper insight into the tool itself. Prospects on program improve­ments and further development complete this thesis.

Abbildungsverzeichnis

Abbildung 1: Veranschaulichung des Qualitätsbegriffs, Quelle: [6]

Abbildung 2: Wasserfallmodell, Quelle: [11]

Abbildung 3: Einteilung der Testverfahren

Abbildung 4: Black-Box-Test, Quelle: [15]

Abbildung 5: White-Box-Test, Quelle: [15]

Abbildung 6: Grey-Box-Test, Quelle: [15]

Abbildung 7: Aufteilung des Wertebereichs

Abbildung 8: Testspezifikation für das Programm Find, Quelle [4]

Abbildung 9: Grenzwertanalyse, Quelle [4]

Abbildung 10: Model-View-Controller Entwurfsmuster, Quelle [19]

Abbildung 11: Datenmodell für die Metainformationen

Abbildung 12: Hierarchische Anordnung der Kulturen, Quelle [21]

Abbildung 13: Ein- und Ausgabeschema für Coco/R, Quelle [22] und [41]

Abbildung 14: Indexstruktur für die Testfallerstellung

Abbildung 15: Erzeugte Metainformationen

Abbildung 16: Erzeugte Vorlage für die Testmethode

Tabellenverzeichnis

Tabelle 1: Formular zur Auflistung der Äquivalenzklassen, Quelle [13]

Tabelle 2: Äquivalenzklassen des Programms Find

Tabelle 3: Testfälle für das Programm Find

Tabelle 4: Erzeugte Testframes bei unabhängigen Partitionen

Tabelle 5: Erzeugte Testframes bei abhängigen Partitionen

Tabelle 6: Tabellarische Testspezifikation für das Programm Find, Quelle [4]

Tabelle 7: Testframes für das Programm Find, Quelle [4]

Tabelle 8: Weitere Eigenschaften in den Metainfo-Klassen

Tabelle 9: Eigenschaften der Klasse TestCase

Tabelle 10: Attribute für das PropertyGrid, Quelle [20]

Tabelle 11: Legende für die Quelltextstatistik

Tabelle 12: Quelltextstatistik C# Dateien

Tabelle 13: Quelltextstatistik AssemblyParser

Tabelle 14: Quelltextstatistik ComponentModel

Tabelle 15: Quelltextstatistik Controls

Tabelle 16: Quelltextstatistik MetaInfo

Tabelle 17: Quelltextstatistik SharpParser

Tabelle 18: Quelltextstatistik TestIt

Tabelle 19: Quelltextstatistik TestSpecParser

Tabelle 20: Quelltextstatistik Util

Tabelle 21: Laufzeitstatistik für Parser (in Millisekunden)

Tabelle 22: Laufzeitstatistik Testfälle erstellen (in Millisekunden)

Danksagung

Ich möchte allen danken, die mir während der Entstehung dieser Diplomarbeit hilfreich und geduldig zur Seite gestanden sind. An erster Stelle gilt der Dank meinem Betreuer
o.Univ.-Prof. Dipl.-Ing. Dr. Hanspeter Mössenböck. Ich bedanke mich für seine Bemühungen, seine Unterstützung und seine fachkundigen Ratschläge.

Ganz besonderer Dank gilt meinen Eltern und meinen Freunden, deren Hilfe und konstruktive Kritik zur Verbesserung der Qualität dieser Diplomarbeit beigetragen haben.

Aufgabenstellung

Beim Black-Box-Test von Software geht es darum, aus der Spezifikation eines Programms Test­fälle abzuleiten, ohne den Quelltext des Programms zu kennen. In der Regel werden diese Test­fälle ad-hoc (d.h. ohne Systematik) ermittelt, was zur Folge hat, dass zahlreiche Test­fälle ver­gessen werden und dass man sich nach Änderungen im Programm die Testfälle wieder neu über­legen muss.

Eine systematische Methode der Testfallgenerierung ist die Äquivalenzklassenanalyse, bei der die Werte der Eingabeparameter eines Programms in Klassen eingeteilt werden, die prinzi­piell das gleiche Verhalten des Programms hervorrufen. Man muss dann das Programm nur mit einem einzigen Wert pro Äquivalenzklasse testen anstatt mit allen Werten dieser Klasse, was die Anzahl der Testfälle erheblich reduziert.

Ziel dieser Diplomarbeit ist ein Werkzeug, das die systematische Ermittlung von Testfällen nach der Äquivalenzklassenanalyse unterstützt. Es verwaltet Testspezifikationen für jede zu testende Methode des Programms (z.B. für die Methode string1.Insert(pos, string2)). Die Test­spezifikationen werden vom Benutzer wie folgt erstellt:

· Man gibt alle Faktoren an, von denen die Methode abhängt, also alle Eingangs- und Ausgangsparameter sowie die globalen Variablen, die Einfluss auf die Methode haben. Für die Methode Insert sind das zum Beispiel die Parameter string1, string2 und pos

· Für jeden Faktor ermittelt man die Äquivalenzklassen, d.h. jene Werte, die prinzi­piell das gleiche Verhalten der Methode hervorrufen. Zum Beispiel fallen die Werte "abc" und "def" für string2 in die gleiche Äquivalenzklasse, hingegen die Werte "abc" und null nicht. Außerdem versucht man Werte zu finden, die eine gewisse Wahrscheinlichkeit aufweisen, einen Fehler in der Methode aufzudecken (z.B. einen leeren String, einen String der Länge 1, einen sehr langen String).

Das Werkzeug ermittelt dann die erforderlichen Testfälle durch Kombination jedes Faktor­werts mit allen Werten der anderen Faktoren.

Um die Anzahl der Testfälle zu reduzieren, kann man Faktorenwerte die zu Fehlerfällen führen oder nur mit bestimmten anderen Faktorenwerten kombiniert werden dürfen, speziell mar­kieren. Diese Faktorenwerte werden dann nicht mit allen anderen Faktorenwerten kombi­niert, was die Anzahl der Testfälle erheblich senkt.

Als Ergebnis liefert das Werkzeug für jede spezifizierte Methode eine Liste von Testfällen, die man dann systematisch z.B. mit einem Werkzeug wie JUnit ausprogrammieren kann.

Die Arbeit ist in Java oder C# zu implementieren und mit einer grafischen Benutzeroberfläche zu versehen.

1 Einleitung

4. Juni 1996 - der Jungfernflug der Ariane 5 endet mit der Sprengung der Rakete cirka

40 Sekunden nach dem Start. Die Fracht, vier Satelliten, ging ebenfalls verloren. Der fi­nan­zi­elle Schaden belief sich ungefähr auf eine halbe Milliarde Euro. Der Selbstzerstörung der Ariane war der komplette Verlust der Steuerkontrolle vorangegangen. Was war passiert?

Das Programm des Navigationsrechners enthielt die Konvertierung einer 64-Bit-Fließkomma­zahl in eine 16 bittige vorzeichenbehaftete Ganzzahl. Wenn die Fließkommazahl zu groß ist, schlägt die Konvertierung fehl. So geschehen während des Starts der Ariane. Die dadurch entstandene Ausnahme­situation wurde vom Rechner nicht behandelt. Diese führte an­schlie­ßend zur Ab­schaltung des Programms, wie in der Spezifikation vorgesehen. Daraufhin über­nahm der zweite Navigations­rechner die Steuerung. Da auf beiden Rechnern die selbe Soft­ware lief, trat wiederum derselbe Fehler auf, welcher ebenfalls zur Abschaltung des Reserve­systems führte. Daraufhin wich die Rakete vom Kurs ab, zerbrach und wurde aus Sicherheits­gründen gesprengt. [1]

Der Überlauf während der Typkonvertierung lässt einen Implementierungsfehler der Software vermuten. Das war jedoch nicht der Fall. Im Gegenteil, der Fehler war in den Anforderungen ver­borgen. Die verwendete Soft­ware für den Navigationsrechner der Rakete enthielt einen Pro­gramm­teil vom Vorgänger­modell Ariane 4. Die Verhaltensweise dieser Software wurde weder mit den Bedingungen der Ariane-5 verglichen, noch gemeinsam mit den anderen Ariane-5-Komponenten getestet. [2]

Das IEEE (Institute of Electrical and Electronics Engineers) unterscheidet drei Begriffe für Fehler, je nachdem wann sie auf dem Weg von der Ursache zur Wirkung auftreten. [3]

- Jeder Fehler (fault) oder Mangel ist seit dem Zeitpunkt der Entwicklung in der Soft­ware vorhanden. (Wiederverwendung eines Programmteils der Ariane-4 Software.)
- Ein Fehler ist aufgrund des fehlerhaften Verhaltens (error) eines Entwicklers ent­standen. (Annahme, dass sich der Programmteil der Ariane-4-Software wieder ver­wenden lässt.)
- Ein Softwarefehler kommt nur bei der Ausführung der Software als Fehlerwirkung (failure) zum Tragen und führt dann zu einer Abweichung des tatsächlichen Pro­gramm­verhaltens vom gewünschten Programmverhalten. (Überlauf bei der Typ­kon­ver­tierung.)

Der Begriff Defekt (defect) fasst alle in einem Softwaresystem auftretenden Fehlerarten zu­sammen. [4] (Anmerkung: Der Begriff Bug (Wanze) als Synonym für Defekt entstand bereits vor der Erfindung des Computers. Im September 1945 entfernte die Mathematikerin Grace Murray Hopper eine Motte aus den Schaltwerken des Rechner-Urahns Havard Mark II. [5])

Defekte verursachen Schäden. Es gibt viele Arten von Schäden, wie finanzielle Schäden (Zer­störung der Sa­tel­liten), wie die Beschädigung des Rufs einer Firma, oder Personen­schäden, wenn bei­spiels­weise ein lebenserhaltendes Gerät fehlerhaft arbeitet. Durch Testen sollen diese De­fekte ge­funden und anschließend durch Debugging (der Begriff stammt von Bug) behoben werden. De­bugging bedeutet eliminieren von Bugs.

Testen ist mit Kosten verbunden. Testen dient dazu, um Defekte zu finden und somit den Wert bzw. die Qualität der Soft­ware zu erhöhen. Die Wertsteigerung soll dabei höher aus­fallen, als die verursachten Kos­ten. Ein Ziel des Testens ist also, möglichst viele Fehler bei möglichst geringem Aufwand zu fin­den. Dies führt zur Frage: Wie entwirft man eine minimale, aber annähernd vollständige Men­ge relevanter Testfälle?

Beim Testfallentwurf wird häufig unsystematisch vorgegangen. Die Testfälle werden ad hoc ent­wickelt und dabei werden nur gültige Ein­gabe­daten getestet. Auf ungültige Eingaben wird oft vergessen. Außerdem werden die Designüberlegungen, die zu den Testfällen geführt haben, weder dokumentiert noch archiviert, um sie später nachvollziehen zu können. Nach Än­derungen im Programm muss man sich die Test­fälle wieder neu überlegen. Dies führt zur nächs­ten Frage: Wie wird beim Testen vorgegangen?

Um Defekte überhaupt zu finden, muss davon ausgegangen werden, dass sie in jeder Software vor­handen sind. Damit ein Softwareentwickler eine entsprechende Geisteshaltung annimmt, müsste er hinnehmen, dass er gerade fehlerhafte Software erstellt hat. So gesehen ist ein Soft­ware­ent­wick­ler nicht als Tester seiner eigenen Software geeignet. Eine weitere Frage lautet: Wer testet?

Ziel dieser Arbeit ist es, die wirtschaftlichen, psychologischen und technischen Aspekte des Testens näher zu behandeln, wobei der Schwerpunkt auf der technischen Seite liegt. Es soll eine Systematik entwickelt werden, um eine minimale, aber möglichst voll­stän­dige Menge re­le­vanter Testfälle für den Black-Box-Test zu entwerfen und zu dokumentieren. An­schlie­ßend sollen aus den Testfällen automatisch Testprogramme erzeugt werden.

2 Grundlagen

Dieses Kapitel definiert zuerst den Begriff Qualität. Im Anschluss daran werden Produkt - und Prozessqualität behandelt, und es wird erklärt, warum sie einander bedingen. Weiters wird auf stan­dardi­sierte Prozessmodelle und wie sie dabei helfen Prozess­qualität sicher­zustellen ein­ge­gangen. Anschließend folgt eine allgemeine Betrachtung des Begriffs Testen für die Um­setzung der Produktqualität. Den Abschluss machen eine Einteilung der Testverfahren, wie sie zur Erhöhung der Softwarequalität beitragen und mit welchen Metriken deren Erfolg ge­messen wird.

2.1 Qualität

Qualität ist die Übereinstimmung von geforderter Beschaffenheit (Qualitätsforderung) und reali­sierter Beschaffenheit (siehe Abbildung 1). Das Niveau der Qualitätsforderung ist dabei nicht aus­schlaggebend. Wird die Qualitätsforderung nicht erfüllt, liegt ein Qualitätsmangel vor. Übersteigt die realisierte Beschaffenheit die Qualitätsforderung, trägt dies nichts zur Er­reichung von Qualitätszielen bei. Grundsätzlich wird zwischen Produktqualität und Prozess­qualität unterschieden. [6]

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 1: Veranschaulichung des Qualitätsbegriffs, Quelle: [6]

2.1.1 Produktqualität

Die Produktqualität beschreibt Qualitätsmerkmale des Produkts. Nach der ISO-Norm 9126 sind dies: [6]

- Änderbarkeit: beschreibt Merkmale, welche die Durchführung von Anpassungen an geänderte Anforderungen ermöglichen.

- Benutzbarkeit: beschreibt Merkmale, welche die Einfachheit oder Schwierigkeit der Nutzung durch den Menschen betreffen.

- Effizienz: beschreibt Merkmale, welche einen ökonomischen Gebrauch von Res­sourcen des unterliegenden Systems ermöglichen.

- Funktionalität: beschreibt Merkmale, welche die Verwendbarkeit bezüglich der vor­handenen Funktionen ausdrücken.

- Übertragbarkeit: beschreibt Merkmale, welche die Eignung für andere Hardware- bzw. Software-Konfigurationen ausdrücken.

- Zuverlässigkeit: beschreibt Merkmale, welche das Verhalten im Fehlerfall be­schreiben.

2.1.2 Prozessqualität

Prozessqualität wird vorausgesetzt, um Produktqualität erreichen zu können. Geringe Prozess­qualität kann daher nicht zu hoher Produktqualität führen. [6] Das SEI (Software Engineering Institute der Carnegie Mellon University) hat mit finanzieller Hilfe des US-Verteidigungs­minis­terium das Capability Maturity Model (CMM) entwickelt. Das CMM klassifiziert mit den fünf Reifegraden die Qualität des Softwareentwicklungsprozesses (SE-Prozesses) in einem Software-Unternehmen.

- Reifegrad 1 (initial): Der SE-Prozess ist instabil und kaum organisiert. Zeitaufwand und Kosten für die Entwicklung werden nur grob geschätzt.

- Reifegrad 2 (repeatable): Der SE-Prozess ist geregelt und wiederholbar. Methoden wie Analyse und Design werden eingesetzt.

- Reifegrad 3 (defined): Der SE-Prozess wird standardisiert und in einzelne Phasen unter­teilt. Das Einhalten des Prozesses wird von einer Prozessgruppe überwacht.

- Reifegrad 4 (managed): Die Suche nach Ursachen für Abweichungen vom Projekt­plan und die ständige Korrektur des SE-Prozesses stehen im Vordergrund.

- Reifegrad 5 (optimized): Der SE-Prozess wird permanent untersucht und optimiert.

Das CMM ist hierarchisch organisiert. Ein Aufstieg zu einem höheren Reifegrad ist durch die Verbesserung der SE-Prozesse möglich. [8] CMM wurde Ende 2003 durch das Capability Maturity Model Integration (CMMI) ersetzt, welches ein modulares und vor allem ver­ein­heit­lichtes Modell für die Integration weiterer Entwicklungs-Disziplinen, wie zum Beispiel Hard­ware-Entwicklung, bietet. [9]

In Europa werden eher die Normen der ISO-9000 Reihe favorisiert. ISO 9000-3 erklärt bei­spiels­weise die Anwendung von Qualitäts­management­systemen auf die Softwareentwicklung. Diese Norm ist dem amerikanischen CMM ähnlich, bietet jedoch keine Qualitätsniveaus. [8]

Damit ein SE-Prozess bei Projektbeginn nicht jedes Mal von Grund auf neu entwickelt werden muss, existieren bereits eine Vielfalt von standardisierten Prozessmodellen. Jedes Prozess­modell hat dabei seine spezifischen Vor- und Nachteile.

2.2 Prozessmodelle

Ein Prozessmodell beschreibt den SE-Prozess vollständig. Es definiert Aktivitäten (Vor­ge­hens­modell) und Rollen (Projektorganisation), die bei der Entwicklung zu durchlaufen sind, und die dabei erzeugten Ergebnisse. [10]

Das einfachste aller Prozessmodelle ist das Wasserfallmodell (siehe Abbildung 2). Es be­schreibt den SE-Prozess als sequenziell zu durchlaufende Phasen. Die nächste Phase wird erst be­gonnen, nachdem die vorherige Phase abgeschlossen wurde. [10] Es erlaubt zwar die Rück­kehr zur vorherigen Phase, falls diese unvollständige Ergebnisse geliefert hat. Ge­samt be­trach­tet ist das Wasser­fall­modell allerdings wenig flexibel. Wenn sich während der Projekt­ab­wi­cklung die An­forderungen an die Software ändern, muss ein komplett neuer Zyklus be­gon­nen werden. [11]

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 2: Wasserfallmodell, Quelle: [11]

Neuere Prozessmodelle legen besonderen Wert auf Flexibilität. Sie werden deshalb auch
agile Prozesse genannt. Im Gegensatz dazu werden die wenig flexiblen SE-Prozesse als schwergewichtig bezeichnet. Agile Prozesse ermöglichen diese Flexibilität durch kurze Versions­zyklen von wenigen Wochen bis Monaten. Der bekannteste Vertreter dieser Kate­gorie von SE-Prozessen ist wohl Extreme Programming (XP). Die typischen Phasen der klassischen Softwareentwicklung (Anforderungen, Analyse, Entwurf, Implementierung, Test) werden in kurzen Zyklen, so genannten Iterationen, durchlaufen. Der Auftraggeber hat daher viel öfter die Möglichkeit, steuernd in das Softwareprojekt einzugreifen. [12]

Allen SE-Prozessen, schwergewichtigen wie agilen, ist gemeinsam, dass sich eine Phase bzw. mehrere Aktivitäten mit dem Testen der Software befassen. Der nächste Abschnitt beschäftigt sich daher mit Grundlagen des Testens.

2.3 Testen

Mit dem Testen von Software wird das Ziel verfolgt, sämtliche Fehler unterschiedlichster Art (siehe Einleitung) aufzuspüren. Das heißt, zu

1. prüfen, ob die Software das tut, was sie tun soll, und zu
2. prüfen, ob sie nicht das tut, was sie nicht tun soll. [13]

Der erste Fall wird Positivtest genannt. Er dient dazu, um zu zeigen, dass die Software ihren Zweck erfüllt. Die zweite Forderung soll die Software zu Fall bringen. Es ist also ein de­struk­tiver Prozess, der auch als Negativtest bezeichnet wird. Ein erfolgreicher Test muss beide Forderungen erfüllen. [14]

Es gilt nun zu beurteilen, wie gut die Tests geeignet sind, Fehler zu finden. Wünschenswert wäre ein Messwert, der eine Aussage über die Qualität der Testfälle zulässt. So ein Mess­wert für die Ausprägung einer Eigenschaft wird als Metrik bezeichnet. Eine Metrik ist eine Maß­zahl für eine Eigenschaft oder ein Qualitäts­merkmal von Software. Beispiele für Quell­text-Metriken sind: Anzahl der Quell­text­zeilen, Komplexitätsmaßzahlen und Lesbarkeit. [9] Mehr dazu im Abschnitt 2.4.

Es stellt sich nun die Frage: Wer testet? Entwurf und Implementierung von Software ist ein konstruktiver Prozess. Psychologisch gesehen wäre es falsch einen Software­entwickler nach erledigter Arbeit zu zwingen, seine eigene Software zu Fall zu bringen. Für eine destruktive Tätigkeit sind daher Außenstehende besser geeignet. Weiters könnte der Softwareentwickler ungenügendes Verständnis für die Problemstellung gehabt haben. In diesem Fall setzt sich das Miss­ver­ständnis in den Tests fort und die Fehler bleiben unentdeckt. [14]

2.4 Testverfahren

Ein Testverfahren ist eine systematische Methode, um Tests zu erstellen und auszuwählen. Ein Verfahren ist effektiv, wenn es geeignet ist, Fehler zu finden. Jedes Verfahren adressiert dabei charakteristische Fehlerarten [14]. Abbildung 3 zeigt eine Einteilung der Verfahren, welche nach­folgend erklärt werden. Die fett umrahmten Testverfahren sind Teil der Auf­gaben­stellung. Sie werden im Kapitel 3 ausführlich er­klärt.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 3: Einteilung der Testverfahren

2.4.1 Statische Verfahren

Statische Verfahren sind dadurch gekennzeichnet, dass das Programm nicht ausgeführt wird. Statt­dessen wird der Quelltext auf bestimmte Merkmale analysiert.

2.4.1.1 Schreibtischtest

Der Tester spielt einzelne Testfälle auf einem Blatt Papier durch. Er liest dabei Schritt für Schritt jede Anweisung im Quelltext und notiert sich das jeweilige Ergebnis. Anschließend vergleicht er das erwartete Ergebnis mit dem tatsächlichen. Dieses Verfahren ist aufwendig, in­effizient und für den Tester langweilig durchzuführen. [4]

2.4.1.2 Quelltext-Inspektion

Inspektionen erfordern in der Regel einige Vorbereitung. Schließlich trifft sich ein Testteam zum Gedankenaustausch und zur visuellen Überprüfung des Programms. Das Testteam besteht gewöhnlich aus vier Mitgliedern, von denen einer der Autor des Programms ist. Au­ßer­dem ist ein Moderator vorgesehen, der nicht der Programmautor sein sollte. Der Moderator ver­teilt einige Tage vor der Inspektionssitzung Unterlagen wie Spezifikation und Quell­text, damit die Teilnehmer genügend Zeit haben, sich mit der Materie auseinanderzusetzen. In der Sitzung erklärt der Autor des Programms schrittweise die Programmlogik. Während des Vor­trags können die Teammitglieder Fragen stellen, um mögliche Fehlerquellen auf­zudecken. Er­fah­rungs­gemäß findet der Softwareentwickler während des Vortrags die Fehler selbst. Der Moderator steuert die Diskussion und achtet darauf, dass sich das Team auf die Fehler­suche und nicht auf deren Korrektur konzentriert. Prüflisten helfen dabei, häufig auftretende Fehler zu finden. Sie sollten ständig überarbeitet und ergänzt werden. [13] Erkannte Schwä­chen im Quelltext sind beispielsweise nicht eingehaltene Programmier­richtlinien und Rück­mel­dungen über den Programmierstil.

2.4.1.3 Komplexitätsanalyse

Die Komplexitätsanalyse beschäftigt sich, wie der Name schon sagt, mit der Komplexität des Quell­texts. Die meisten Komplexitätsmaße lassen sich vom Steuerfluss des Programms ab­leiten. Das wohl bekannteste Maß ist die zyklomatische Komplexität nach McCabe. Bei diesem Verfahren wird der Steuerfluss als Graph dargestellt. Die Komplexitätsmaßzahl hängt von der Anzahl der Knoten, Anzahl der Kanten zwischen den Knoten und der Anzahl der nicht verbundenen Teilgraphen ab. [14] Andere Maße berücksichtigen die Anzahl der Daten­typen, Verzweigungen und die Verschachtelungstiefe. Weiters versuchen Werkzeuge zur Quell­textanalyse schwächen im Quelltext bzw. unsauberen Programmierstil und damit poten­tielle Fehlerquellen aufzudecken.

2.4.2 Dynamische Verfahren

Im Gegensatz zu den statischen Testverfahren wird bei den dynamischen Verfahren das Programm ausgeführt. In [13] wird Testen folgendermaßen definiert: Testen ist der Prozess, ein Programm mit der Absicht auszuführen, Fehler zu finden. Die bedeutendste Metrik für dyna­mische Verfahren ist die Testabdeckung. Als Testabdeckung bezeichnet man das Ver­hältnis von tatsächlich getroffenen Aussagen eines Tests zu den theoretisch möglichen Aus­sagen. Die Testabdeckung kann durch verschiedene Faktoren beeinflusst werden. Durch eine höhere Anzahl an Testfällen lässt sich die Abdeckung verbessern. In der Praxis wird die Test­abdeckung jedoch durch den Testaufwand und den damit verbundenen Kosten begrenzt. [9]

2.4.2.1 Black-Box-Test

Das wesentliche Merkmal von Black-Box-Tests ist, dass die interne Struktur eines Pro­gramms entweder nicht bekannt ist, oder ignoriert wird. Das Programm­verhalten wird anhand der Spezifikation getestet. Das bedeutet, dass die Testdaten aus der Spezifikation abgeleitet werden. Abbildung 4 verdeutlicht dies grafisch.

Wichtige Metriken für die Testabdeckung von Black-Box-Tests sind:

- Abdeckung aller Funktionen: jede spezifizierte Funktion wird in mindestens einem Testfall ausgeführt.
- Abdeckung aller Eingaben: für jede Funktion wird jeder Eingabewert mindestens in einem Testfall verwendet.
- Abdeckung aller Ausgaben: für jede Funktion wird jeder Ausgabewert in mindestens einem Testfall erzeugt.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 4: Black-Box-Test, Quelle: [15]

Um mit diesem Verfahren alle Fehler in einem Programm zu finden, müssten alle möglichen Eingabewerte zum Testen verwendet werden. Dies ist jedoch unmöglich, denn selbst bei einem ganzzahligen Wert gäbe es theoretisch unendlich viele Testwerte. Daraus ergeben sich zwei Folgerungen:

1. Man kann im Allgemeinen ein Programm nicht mit allen möglichen Eingaben testen, da es unendlich viele davon geben könnte. Somit kann man durch Tests nicht zeigen, dass alle eingaben das korrekte Ergebnis liefern.
2. Ein wesentlicher Aspekt beim Testen ist die Wirtschaftlichkeit.

Charakteristisches Merkmal der Black-Box-Testverfahren ist es, die Anzahl der Testfälle so einzuschränken, dass mit den verbleibenden die maximale Anzahl an Fehlern gefunden wird. Die beiden Verfahren Äquivalenzklassenanalyse und Grenzwertanalyse verfolgen genau dieses Ziel und werden im Kapitel 3 erklärt. [13]

2.4.2.2 White-Box-Test

White-Box-Tests berücksichtigen die interne Struktur eines Programms. Der Tester formuliert die Testfälle mit Kenntnis des Quelltexts selbst oder des darauf basierenden Algorithmus (siehe Abbildung 5). [13]

Wichtige Metriken für die Testabdeckung von White-Box-Tests sind:

- Abdeckung aller Anweisungen: Führt jede Anweisung mindestens einmal aus.
- Abdeckung aller Verzweigungen: Jede Verzweigungsalternative wird mindestens einmal ausgeführt. Eine If-Else -Verzweigung weist zwei mögliche Pfade auf.
- Abdeckung aller Bedingungen bei Verzweigungen: Jede Verzweigungsbedingung muss mindestens einmal wahr und einmal falsch gewesen sein. Bei zwei Bedingungen in einer If-Else -Verzweigung ergeben sich 2² = 4 Möglichkeiten. Beispiel: if (a&b)

Abbildung in dieser Leseprobe nicht enthalten

- Abdeckung aller Pfade: Jeder mögliche Kontrollflusspfad durch das Programm muss mindestens einmal durchlaufen werden. Im Allgemeinen ist dies unmöglich, wenn bei­spielsweise die Anzahl an Schleifendurchläufen durch eine unbekannte Größe be­stimmt wird.

Wie die angeführten Beispiele belegen, nimmt die Anzahl an Möglichkeiten von der An­weisungs­abdeckung bis zur Pfadabdeckung kontinuierlich zu. Werkzeuge messen meist nur Abdeckung auf Anweisungs- bzw. Verzweigungsebene. [4]

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 5: White-Box-Test, Quelle: [15]

2.4.2.3 Grey-Box-Test

Grey-Box-Tests verbinden die Vorteile der White-Box-Tests mit denen der blackbox­orientierten Verfahren. [13] White-Box daher, weil der Softwareentwickler auch die Tests schreibt und eventuell doch einige Implementierungsdetails, wie den der Software zugrunde liegenden Algorithmus, kennt. Black­box­orientiert, weil die Tests vor der Implementierung der Software geschrieben werden und daher der Quelltext noch nicht bekannt ist. [9] Abbildung 6 stellt den Zusammenhang grafisch dar.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 6: Grey-Box-Test, Quelle: [15]

3 Im Werkzeug umgesetzte Testverfahren

In diesem Kapitel werden die für die Aufgabenstellung relevanten Verfahren zur systema­tischen und automatisierten Testfallerzeugung vorgestellt. Der Benutzer des Werkzeugs er­stellt aus der Spezifikation der zu testenden Funktion eine maschinenlesbare Test­spezifikation mittels Äquivalenzklassenanalyse. Das Werkzeug liest die Testspezifikation ein und erstellt daraus Testframes. Konkrete Testwerte werden mittels Grenzwertanalyse ermittelt. An­schlie­­ßend werden die Testframes und Testwerte zu Unit-Tests zusammengefügt.

3.1 Äquivalenzklassenanalyse

Wie im Abschnitt 2.4.2.1 erwähnt, existieren drei Abdeckungsmaße für Black-Box-Tests. Die Funk­tionsabdeckung ist einfach zu erreichen, indem beispielsweise jede Methode einer Klasse getestet wird. Schwieriger, wenn nicht unmöglich, ist es, die Abdeckung aller Ein­gaben bzw. Ausgaben zu bewerkstelligen, weil die Anzahl der möglichen Testfälle ins Un­endliche gehen kann. Es ist daher unausweichlich, aus der Menge an möglichen Testfällen, jene heraus­zufinden welche

1. eine gewisse Wahr­scheinlichkeit zum Auffinden von Fehlern aufweisen.
2. die Anzahl anderer notwendiger Testfälle reduzieren.
3. eine große Menge andere Testfälle überdecken.

Punkt zwei sagt aus, dass jeder Testfall so viele unterschiedliche Eingabebedingungen wie möglich in Betracht ziehen sollte. Der dritte Punkt impliziert, dass der Wertebereich für Ein­gaben in eine endliche Anzahl an Untermengen, auch Äquivalenzklassen oder Partitionen ge­nannt, unterteilt wird. Abbildung 7 zeigt die Aufteilung des gesamten Wertebereichs in ein­zelne Partitionen grafisch.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 7: Aufteilung des Wertebereichs

Diese Aufteilung geschieht unter der Annahme, dass ein repräsentativer Wert einer be­stimmten Äquivalenzklasse genauso gut geeignet ist, Fehler zu finden bzw. auszuschließen, wie jeder andere Wert auch. Das heißt, wird durch einen Repräsentanten aus einer Klasse ein Fehler gefunden, so wird dies auch von jedem anderen Wert in der Klasse erwartet. Das Auf­stellen von Testfällen erfolgt in zwei Schritten:

1. Bestimmen der Äquivalenzklassen.
2. Definition der Testfälle.

3.1.1 Bestimmen der Äquivalenzklassen

Zum Festlegen der Äquivalenzklassen verwendet man eine Eingabebedingung oder externe Bedingung, welche üblicher­weise in der Spezifikation durch einem Satz oder Abschnitt reprä­sentiert wird, und teilt diese in Gruppen auf. Es sind mindestens zwei Gruppen, nämlich gültige und ungültige Partitionen. Diese Gruppen können bei Bedarf weiter unterteilt werden. Tabelle 1 ist bei der Auf­listung der Äquivalenzklassen behilflich.

Abbildung in dieser Leseprobe nicht enthalten

Tabelle 1: Formular zur Auflistung der Äquivalenzklassen, Quelle [13]

Äquivalenzklassen beziehen sich auf eine Eingabebedingung oder externe Bedingung aus der Spezifikation. Daher wird die Art und Menge der Partitionen von diesen Bedingungen be­stimmt. Folgende Einteilung hilft beim Auffinden der Äquivalenzklassen:

- Wertebereich: Beispielsweise kann eine Variable einen Wert zwischen 1 und 999 an­nehmen. Daraus ergeben sich eine Partition mit gültigen Werten (1 <= Wert <= 999), sowie zwei Partitionen mit ungültigen Werten (Wert < 1 und 999 < Wert).
- Anzahl von Werten: Bei einer Anzahl von Werten (zum Beispiel: 1 bis 6 Eigen­tümer) wird ähnlich verfahren. Folglich werden eine Partition mit gültigen Werten (1 bis 6 Eigentümer) sowie zwei Partitionen mit ungültigen Werten (kein Eigentümer, mehr als 6 Eigentümer) abgeleitet.
- Menge von Werten: Bei einer Menge von Werten (zum Beispiel: ein KFZ kann PKW, LKW oder Motorrad sein) wird für jede Alternative eine Äquivalenzklasse erstellt. Zu­sätzlich zu den gültigen Partitionen wird eine ungültige Klasse mit einer nicht ge­nannten Möglichkeit hinzugefügt.
- Muss-Bedingung: Für eine Muss-Bedingung wird je eine Partition, welche die Be­din­gung erfüllt bzw. nicht erfüllt, erstellt. Für die Bedingung „das erste Zeichen muss ein Buchstabe sein“ wird eine Klasse für „erstes Zeichen ist ein Buch­stabe“ und eine weitere für „erstes Zeichen ist kein Buchstabe. erzeugt.

3.1.2 Definition der Testfälle

Der zweite Schritt umfasst die Definition der Testfälle:

- Jeder Äquivalenzklasse wird eine eindeutige Nummer zugewiesen.
- Aus den bisher nicht behandelten gültigen Klassen wird ein neuer Testfall erstellt, der möglichst viele weitere unbehandelte Klassen abdeckt. Dies wird so lange wiederholt, bis alle Äquivalenzklassen durch Testfälle abgedeckt sind. Die Auswahl der Testwerte kann beispiels­weise durch Grenzwertanalyse erfolgen (siehe Abschnitt 3.3).
- Aus jeder ungültigen Äquivalenzklasse wird jeweils ein gesonderter Testfall erstellt.

Ungültigen Klassen kommt durch die Einzeltests besonders Augenmerk zu. Das geschieht aus dem Grund, weil fehlerhafte Eingaben nicht gemeinsam mit weitern fehlerhaften Eingaben ge­testet werden sollen. Es könnte sonst passieren, dass eine fehlerhafte Eingabe durch eine andere ver­hüllt wird. Falls zum Beispiel die Spezifikation den Satz „Geben Sie den Buchtyp (ge­bunden, Taschenbuch, lose) und die Anzahl (1-9999) ein“ enthält, würde beim Testfall Buchtyp=xyz und Anzahl=0 beispielsweise nach der fehlgeschlagenen Prüfung des Buchtyps das Programm abgebrochen. Die fehlerhafte Anzahl würde daher nicht mehr geprüft. [13]

3.1.3 Beispiel

Das Programm Find sucht ein gegebenes Muster in einer Datei. Alle Zeilen, die das Muster ent­halten, werden am Bildschirm ausgegeben. Wenn eine Zeile das Muster mehrfach enthält, wird es trotzdem nur einmal ausgegeben. Syntax: Find <Muster> <Datei>

Das Muster ist eine beliebige Zeichenkette, die nicht länger als die maximale Zeilenlänge der Sätze in der Datei sein darf. Wenn das Muster Leerzeichen enthält, muss es unter Hoch­komma (" ") ge­schrieben werden. Ein Hochkomma im Muster selbst wird durch Voranstellen eines Schräg­striches (\") angegeben. [16]

Abbildung in dieser Leseprobe nicht enthalten

Tabelle 2: Äquivalenzklassen des Programms Find

Durch die Analyse der Spezifikation lassen sich externe Bedingungen und Äquivalenzklassen, wie in Tabelle 2 gezeigt, identifizieren. Jede Äquivalenzklasse hat eine eindeutige Nummer, die in Klammern neben der Äquivalenzklasse angeführt ist.

Im nächsten Schritt werden Testfälle erstellt, die eine oder mehrere Äquivalenzklassen ab­decken. Jede ungültige Äquivalenzklasse wird gesondert getestet. Tabelle 3 zeigt die erstell­ten Testfälle für gültige sowie ungültige Eingaben. Neben jedem Testfall sind die abge­deckten Äquivalenzklassen aufgelistet.

Abbildung in dieser Leseprobe nicht enthalten

Tabelle 3: Testfälle für das Programm Find

Zu den Testfällen in Tabelle 3 ist noch Anzumerken, dass eine Datei namens file_not_found nicht existieren darf bzw. die Datei valid_file eine gültige Datei darstellt.

3.2 Category-Partition Methode

Eine systematischere Vorgehensweise bei der Erstellung von Äquivalenzklassen verfolgt die Category-Partition Methode. [16] Dabei wird die in einer natürlichen Sprache verfasste Spe­zi­fikation, welche unmittelbar als Basis für Black-Box-Tests ungeeignet ist, in eine formale Sprache über­setzt. Während der Transformation der Spezifikation fallen häufig un­voll­ständige, mehrdeutige oder widersprüchliche Formulierungen auf. Dieser Über­setzungs­pro­zess hilft daher auch die Qualität der Spezifikation zu verbessern, indem die vorher ge­nannten Probleme aufgedeckt werden. Weiters werden nicht nur die Eingabedaten, sondern auch die Ausgabedaten bei den Tests berücksichtigt.

Die Category-Partition Methode beginnt mit der Zerlegung der Spezifikation in funktionale Einheiten, die unabhängig getestet werden können. Im Fall einer Klasse (im Sinne der objekt­orientierten Programmierung) wäre eine solche funktionale Einheit eine Methode. Der nächste Zerlegungsschritt ermittelt die Parameter und Umgebungseinflüsse, welche das Verhalten der funktionalen Einheit beeinflussen. Parameter sind explizite Eingaben, während Umgebungs­einflüsse beispielsweise globale Variablen oder den Systemzustand beschreiben. Parameter und eventuell vorhandene Umgebungseinflüsse werden unter dem Begriff Faktor zusammen­gefasst. Für diese Faktoren müssen konkrete Werte gefunden werden, um Testfälle erstellen zu können. Auf der Suche nach diesen Werten werden im nächsten Schritt des Zer­legungs­prozesses Arten von Informationen gesucht, die jeden Faktor kennzeichnen. Der Tester markiert in der Spezifikation für jeden Faktor jene Textstellen, die das Verhalten der funk­tionalen Einheit beeinflussen. Jedes erkannte Merkmal wird als Category bezeichnet. Im nächsten Schritt werden die gefundenen Merkmale in Äquivalenzklassen (Choices) unterteilt. Die Begriffe Äquivalenzklasse, Partition sowie Choice haben dieselbe Bedeutung.

Nachdem Faktoren und Äquivalenzklassen feststehen, wird für jede funk­tio­nale Einheit eine formale Testspezifikation verfasst. Die Testspezifikation besteht aus einer Liste von Faktoren, die eine Liste von Partitionen enthält. Aus der Testspezifikation werden im nächsten Schritt Testframes für die Testfälle erstellt. Vorerst wird bei der Erstellung der Testframes so vor­ge­gangen, dass jede Äquivalenzklasse mit jeder anderen Partition, die nicht zum selben Faktor ge­hört, kombiniert wird. Im Abschnitt 3.1.2 wird diese Vorgehensweise noch erweitert.

3.2.1 Unabhängige Partitionen

Den einfachsten Fall stellen unabhängige Partitionen dar. Aus einer Testspezifikation mit zwei Faktoren (Faktor 1 und Faktor 2), die jeweils zwei Äqui­valenz­klassen (Partition1 und Partition 2) enthalten, kann man vier Testframes ableiten. Tabelle 4 zeigt die erstellten Test­frames. Beispielsweise wird Partition 1 von Faktor 1 wegen der besseren Über­sicht­lich­keit als F1_P1 be­zeichnet.

Abbildung in dieser Leseprobe nicht enthalten

Tabelle 4: Erzeugte Testframes bei unabhängigen Partitionen

Im Testframe ist jedem Faktor genau eine Partition zugeordnet. Die Anzahl der erzeugten Test­frames erhält man, indem man die Anzahl an Partitionen jedes Faktors miteinander multi­pliziert.

3.2.2 Abhängige Partitionen

Im Allgemeinen sind Faktoren bzw. deren Partitionen voneinander abhängig. Ein einfaches Beispiel dafür sind die einzelnen Elemente des Datums. Es gibt Monate mit 30 Tagen, während andere Monate 31 Tage aufweisen. Die Anzahl der Tage ist offensichtlich vom Monat abhängig; nicht nur vom Monat, sondern auch vom Jahr. In Schaltjahren hat der Februar 29 Tage, andernfalls 28 Tage. Im Falle des 29. Februars ist der Tag also von Monat und Jahr abhängig. Für das Erstellen des Testframes ergibt sich daher die Notwendigkeit, dass einige Äquivalenzklassen nicht mit be­stimmten anderen Partitionen kombiniert werden dürfen. Diese Ein­schränkungen (Constraints) müssen ebenfalls in die Testspezifikation auf­ge­nommen werden.

Zur Demonstration soll das vorherige Beispiel mit unabhängigen Partitionen um eine Ein­schränkung zwischen F1_P1 und F2_P2 erweitert werden. F2_P2 soll von F1_P1 abhängig sein. F1_P1 wird daher als Bezugspartition und F2_P2 als abhängige Partition bezeichnet. Be­ziehungen zwischen Äquivalenzklassen werden in der Testspezifikation durch das zu­sätzliche Attribut Property in der Be­zugs­partition und einer If -Bedingung in der abhängigen Partition realisiert. Die If -Bedingung enthält den Bezeichner der Bezugspartition.

F1_P1 [property Dependent]

F2_P2 [if Dependent]

Verknüpfungen von mehreren Äquivalenzklassen, wie es im Datumsbeispiel notwendig wäre, sind mithilfe des binären Und -Operators möglich. Oder -Verknüpfungen sind real­isierbar, in­dem bei mehreren Bezugspartitionen dasselbe Property -Attribut gesetzt wird.

Wegen der soeben definierten Beziehung zwischen F1_P1 und F2_P2 werden nur drei Test­frames erstellt. Das in Tabelle 5 grau hinterlegte Testframe fällt durch die Ein­schränk­ung, dass F2_P2 nur mit F1_P1 kombiniert werden darf, weg.

Abbildung in dieser Leseprobe nicht enthalten

Tabelle 5: Erzeugte Testframes bei abhängigen Partitionen

Die im Abschnitt 2.3 gestellte Forderung, auch ungültige Eingaben zu testen, wird durch die Test­spezifikation ebenfalls berücksichtigt. Hierfür wird eine Partition, die fehlerhafte Ein­gaben enthält, mit dem Attribut Error versehen.

Als weiteres Attribut steht dem Tester Single zur Verfügung. Mit der Anzahl an Partitionen steigt die Anzahl der daraus erzeugten Testframes exponentiell an. Eine Variante der Test­fall­reduktion besteht darin, eine Partition nicht mit allen möglichen anderen zu kombinieren. In manchen Fällen reicht es aus, dass eine bestimmte Partition nur durch einen Testfall abge­deckt ist. Genau diesen Sachverhalt drückt das Single -Attribut aus. Jene Äquivalenzklasse, die mit diesem Attribut versehen ist, kommt in nur einem Testfall vor. Das Single -Attribut wird eben­falls für spezielle oder ungewöhnliche Eingaben eingesetzt. So stellt beispielsweise der Zahlenwert Null für manche Berechnungen einen Spezialfall dar, bei dem die Verwendung des Single -Attributs zweck­mäßig ist.

Äquivalenzklassen, die mit den Attributen Error bzw. Single versehen sind, werden als Spe­zi­al­fälle bezeichnet. Der Begriff kommt daher, weil diese beim Erstellen der Testframes eine be­sondere Vorgehensweise erfordern. Spezialfälle dürfen nicht mit beliebigen anderen Par­ti­tionen kombiniert werden, sondern nur mit Nicht -Spezialfällen. Diese For­de­rung kommt daher, weil einerseits fehlerhafte Eingaben und andererseits Spezialfälle ge­son­dert ge­testet werden sollen.

Zusammenfassend sind folgende Schritte zur Erstellung einer Testspezifikation erforderlich:

1. Analysieren der Spezifikation.

- Funktionale Einheiten ermitteln.
- Faktoren zu jeder funktionalen Einheit ermitteln.
- Eigenschaften jedes Faktors identifizieren.

2. Den Wertbereich der Faktoren in Partitionen unterteilen.

3. Beziehungen zwischen den Partitionen und Spezialfälle bestimmen.

3.2.3 Beispiel

Als Spezifikation soll wieder jene des Programms Find herangezogen werden. Tabelle 6 zeigt die aus der Spezifikation des Programms abgeleitete Testspezifikation. Spezialfälle sind kur­siv, fehler­hafte Eingaben fett hervorgehoben. Die Beziehungen basieren auf folgenden im­pli­ziten An­nahmen:

- Muster mit der Länge Null sowie Leerzeichen bzw. Hochkommas im Muster sind nur möglich wenn das Muster in Hochkommas steht.
- Eine Ausgabe ist nur möglich, wenn sowohl das Muster als auch die zu durchsuchende Datei gültig sind.
- Die Ausgabe der Vorkommen pro Zeile ist nur möglich, wenn das Musters mindestens einmal in der Datei vorkommt.

Abbildung in dieser Leseprobe nicht enthalten

Tabelle 6: Tabellarische Testspezifikation für das Programm Find, Quelle [4]

Für die automatisierte Erstellung der Testframes mittels eines Werkzeugs muss die Test­spe­zi­fi­kation in eine maschi­nen­lesbare Form gebracht werden. Das heißt, dass beispielsweise statt der farblichen Hervor­hebung der Spezialfälle die vorhin vorgestellten Attribute Error bzw. Single zum Einsatz kommen.

Länge des Musters:

0 [single] [if hochkomma]

1 [property muster]

1 < Länge < max. [property muster]

> max. Länge [error]

Muster in Hochkomma:

ja [property hochkomma]

nein [if muster]

falsche Hochkomma [error]

Leerzeichen im Muster:

ja [single] [if hochkomma]

nein

Hochkommas im Muster:

ja [single] [if hochkomma]

nein

Dateiname:

gültig [property datei]

nicht gefunden [error]

nicht angegeben [error]

Anzahl der Zeilen mit Vorkommen:

0 [single]

1 [if muster & datei] [property gefunden]

> 1 [single] [if muster & datei] [property gefunden]

Anzahl der Vorkommen pro Zeile:

1 [if gefunden]

> 1 [single] [if gefunden]

Abbildung 8: Testspezifikation für das Programm Find, Quelle [4]

Die Anzahl der Testfälle erhält man, indem man die Anzahl an Partitionen pro Faktor ohne Spezial­fälle miteinander multipliziert. Anschließend wird die Gesamtanzahl an Spezial­fällen hinzuaddiert. Weitere Einschränkungen durch Beziehungen zwischen den Äqui­valenz­klassen sind in der Berechnung nicht berücksichtigt. Die berechnete Anzahl an Test­fällen stellt also die Maximalanzahl dar. Falls das Werkzeug zu viele Testframes erstellt hat, können diese durch Einführen von Beziehungen bzw. Spezialfällen in der Testspezifikation auf ein an­nehm­bares Maß reduziert werden. Für das angeführte Beispiel sind das 4+6=10 Spezialfälle und 2×2×1×1×1×1×1 = 4 weitere Testframes. Tabelle 7 zeigt die durch das Werk­zeug er­stell­ten Testframes.

Abbildung in dieser Leseprobe nicht enthalten

Tabelle 7: Testframes für das Programm Find, Quelle [4]

Aus den Testframes werden im letzten Schritt konkrete Testfälle formuliert. Dabei wird aus jeder Äquivalenzklasse ein repräsentativer Wert ausgewählt, der im erstellten Testfall als Test­wert dient. Zur Auswahl der Re­präsentanten hat sich die Methode der Grenzwertanalyse be­währt.

3.3 Grenzwertanalyse

Erfahrungsgemäß finden Testfälle, die an den Grenzen von Wertebereichen testen, mehr Fehler als jene, bei denen beliebige Testwerte gewählt werden. Es handelt sich hierbei um typische um-eins-daneben Fehler, wie sie bei Schleifen häufig auftreten. Auch Feldvariablen (Arrays) sind anfällig für diese Art von Fehlern. Beginnt die Indizierung bei Null, entspricht der höchste erlaubte Index nicht der Länge des Feldes, sondern um eins weniger. Soll auf das erste Element zugegriffen werden, ist der entsprechende Index nicht eins, sondern null. Test­werte sollten genau an der Grenze und un­mittel­bar oberhalb bzw. unterhalb der Grenze ge­wählt werden. Abbildung 9 zeigt diesen Sach­verhalt grafisch.

Abbildung in dieser Leseprobe nicht enthalten

Abbildung 9: Grenzwertanalyse, Quelle [4]

Die Grenzwertanalyse kann als eigenständiges Testverfahren oder auch in Ver­bindung mit der Äquivalenzanalyse verwendet werden. Letztere Variante vereint die Vorteile beider Ver­fahren, indem nicht ein beliebiger Wert gewählt wird, sondern an den Grenzen der Partitionen ge­testet wird. [13] Die Grenzwertanalyse steigert ebenfalls die Effektivität der Category-Partition Methode, weil dieses Verfahren ebenfalls auf Äqui­valenz­klassen basiert.

3.4 Unit-Tests

Mithilfe von Modultests werden einzelne Programmteile getestet, statt das Programm als Ganzes zu testen. Modultests folgen damit dem Bottom-Up Ansatz. Erst wenn in den kleinsten Pro­grammeinheiten (Units) keine Fehler mehr gefunden werden, werden sie zu grö­ßeren Pro­gramm­teilen zusammengefügt. Aufgetretene Fehler sind in kleinen Einheiten viel leichter zu finden und zu beheben als in großen, weil der Umfang der Suche nur auf diese kleine Programmeinheit beschränkt bleibt.

Modultests bzw. Unit-Tests wurden durch den Einsatz in Extreme Programming (XP) populär. Mit den Akzeptanztests bilden sie die Basis für die Qualitätssicherung. Zum Beispiel sind zwei der zwölf Kern­prin­zipien von XP sind dem Testen gewidmet: [13]

- Fortlaufende Tests: Ein Modul ist erst fertig, wenn es die Unit-Tests besteht. Die fertige Soft­ware muss alle Unit-Tests und Akzeptanztests erfolgreich absolvieren.
- Fortlaufende Integration: Jeden Tag werden alle erfolgreich getesteten Module zu­sam­mengefügt.

Mithilfe der Unit-Tests lässt sich die Fehlersuche wesentlich beschleunigen und auto­mati­sieren. Die Tests lassen sich be­liebig oft wiederholen und bieten so eine Art Sicherheitsnetz für den Soft­ware­entwickler. Es lassen sich die bisher programmierten Module auf Knopf­druck testen, ob das Programm noch ordnungsgemäß funktioniert. Auch leichtfertige Ände­rungen am Pro­gramm werden auf diese Weise schnell aufgedeckt. [17]

4 Benutzerhandbuch

4.1 Einführung in TestIt

TestIt ist ein Werkzeug für den Black-Box-Test, das Sie beim systematischen Erstellen von Test­fällen für den Unit- und Integrationstest unterstützt. Der Benutzer beschreibt dazu für jede zu testende Funktion die erlaubten Parameterwerte in Form von Äquivalenzklassen. TestIt erstellt daraus alle relevanten Testfälle. Der Benutzer muss nur noch für jeden dieser Test­fälle das erwartete Ergebnis spezifizieren, abschließend kann er mit TestIt die Testfälle in unter­schiedlicher Form (zum Beispiel als NUnit-Testmethoden im Quelltext oder als textuelle HTML-Dokumentation) ausgeben. Das Ausgabeformat kann durch Mustertexte, so genannte Quell­text-Vorlagen, variabel gestaltet werden. Durch den Gebrauch von Quelltext-Vorlagen ist das Programm unabhängig vom eingesetzten Testframework und der verwendeten Pro­grammier­sprache. Darüber hinaus ist die textuelle Beschreibung viel abstrakter als Quelltext. Somit können Sie die Testfälle bereits zu einem sehr frühen Zeitpunkt im Software­ent­wick­lungs­prozess formulieren.

Falls die zu testende Klasse als Quelltext oder Assembly vorliegt, wird diese durch TestIt auto­matisiert analysiert und die Informationen über deren Eigenschaften, Methoden und Para­meter (so genannte Metainformationen) extrahiert. Die Klasse selbst muss nicht vollständig im­plementiert sein. So genügt es beispielsweise, den Quelltext einer Klasse zu importieren, der nur aus den Methodenköpfen bzw. der Schnittstellenbeschreibung besteht. Natürlich kön­nen Sie die Metainformationen auch manuell eingeben. TestIt erzeugt aus den Meta­in­for­ma­tionen automatisch alle erforderlichen Testfälle mittels Äquivalenzklassenanalyse. An­schlie­ßend vervollständigen Sie die Testfälle und formulieren den Testablauf. Darüber hinaus kön­nen Sie die Tests direkt von TestIt ausführen lassen.

Dieses Benutzerhandbuch soll weder in das Thema Testen einführen noch Prinzipien des Testens erklären. Ein gewisses Vorwissen zu diesem Thema ist daher unerlässlich. Eine gute Ein­führung bietet das Buch "The Art of Software Testing" von G. Myers oder "Lessions Learned in Software Testing" von C. Kara, J. Bach und B. Bettichord. Der Aufbau der ein­zelnen Abschnitte ist so gewählt, dass in der Einleitung jedes Abschnitts die folgenden Unter­abschnitte zusammengefasst werden bzw. eine Empfehlung abgegeben wird, wie dieser Ab­schnitt gelesen werden sollte.

In diesem Abschnitt werden folgende Themen behandelt:

- Systemvoraussetzungen: Dieser Abschnitt informiert Sie über die minimalen Sys­tem­voraussetzungen für Hard- und Software, um TestIt einsetzen zu können.

- Installation: Dieser Abschnitt enthält eine Installationsanleitung für TestIt. Sofern Sie mit der Installation von Programmen vertraut sind, können Sie diesen Teil über­springen.

4.1.1 Systemvoraussetzungen

Hardware

Abbildung in dieser Leseprobe nicht enthalten

Software

Abbildung in dieser Leseprobe nicht enthalten

4.1.2 Installation

Damit Sie TestIt verwenden können, müssen Sie das Programm auf Ihrer Festplatte in­stall­ieren. Um TestIt zu installieren, führen Sie bitte folgende Schritte aus:

1. Schließen Sie alle laufenden Programme.
2. Legen Sie die Installations-CD in Ihr CD-Laufwerk ein.
3. Vom Startmenü wählen Sie Ausführen.
4. Tippen Sie D:\setup (ersetzen sie D mit dem Laufwerksbuchstaben Ihres CD-Lauf­werks).
5. Folgen Sie den Anweisungen auf dem Bildschirm.

Standardmäßig wird TestIt in das Verzeichnis C:\Programme\TestIt installiert.

4.2 Funktionsweise

Dieser Abschnitt erklärt die grundlegende Funk­tions­weise von TestIt. Selbst wenn Sie bereits mit der Äquivalenzklassenanalyse vertraut sind, benötigen Sie das hier vermittelte Wissen für den Einsatz von TestIt. Zum Durchführen von Tests sind Testdaten und eine Beschreibung des Testablaufes erforderlich. Es geht also um die Frage, wie die Testdaten zum Testen ein­ge­setzt werden. Daher ist die Funktionsweise von TestIt in die folgenden zwei Teile gegliedert:

- Erzeugen der Testdaten: Testdaten sind die Grundlage für Tests. Hier erfahren Sie, wie der Algorithmus zum Erzeugen der Testdaten arbeitet.
- Erzeugen des Testablaufs: Im zweiten Schritt wird der Testablauf formuliert. Dieser beschreibt, wie die Testdaten für die Tests eingesetzt werden. Das Resultat aus Testdaten und Testlauf sind die Testklassen.

4.2.1 Erzeugen der Testdaten

Der Algorithmus zum Erzeugen der Testdaten basiert auf dem Artikel "The category-partition method for specifying and generating functional tests" von Thomas J. Ostrand und M. Balcer sowie dem Buch "The Art of Software Testing" von G. Myers.

Zusammengefasst besteht die Vorgehensweise zum Erstellen der Testdaten aus folgenden Schritten:

1. Finde die zu testenden Funktionen (Methoden).
2. Finde für jede Funktion alle Ein- bzw. Ausgangsgrößen (Faktoren).
3. Finde für jeden Faktor die dazugehörigen Äquivalenzklassen (Partitionen).
4. Wähle für jede Äquivalenzklasse einen Wert aus (zum Beispiel durch Grenz­wert­analyse) und bilde die Testfälle durch Kombination der Faktorwerte.

- Gültige Faktorwerte sollten mit allen anderen gültigen Faktorwerten kom­biniert werden.
- Ungültige Faktorwerte (Fehlerfälle, Sonderfälle) sollten nicht mit an­deren ungültigen Faktorwerten kombiniert werden. Es genügt, sie ein­mal zu testen.

Für die Schritte 1 bis 3 werden Metainformationen benötigt. Die Metainformationen sind in diesem Fall Funktionen, Faktoren, Äquivalenzklassen und Testwerte. Eine Klasse im Sinne der objektorientierten Programmierung besteht aus Methoden. Diese Methoden wiederum aus Para­metern. Diese drei Begriffe gilt es, mit den bereits erwähnten Metainformationen in Ver­bindung zu bringen. Daher entsprechen die Methoden den Funktionen bzw. Parameter den Fak­toren. Nachstehendes Diagramm stellt die Zusammenhänge grafisch dar. Die hier fehl­enden Eigenschaften sind vorerst nicht wichtig. Sie werden im Abschnitt Erstellen der Meta­in­formationen aufgelistet.

Abbildung in dieser Leseprobe nicht enthalten

Die nachfolgende Abbildung zeigt beispielsweise die Metainformationen für die Klasse Util mit der Methode Power. Power potenziert die Zahl val mit dem Exponenten exp.

Abbildung in dieser Leseprobe nicht enthalten

Um aus den bisherigen Metainformationen Testfälle erzeugen zu können, fehlen noch kon­krete Werte für die Faktoren. Da erschöpfendes Testen unmöglich ist, ist eine Vor­gehens­weise erforderlich, welche diese Unvollständigkeit weitgehend reduziert. Es soll also jene Teil­menge aller denkbaren Testfälle gefunden werden, welche die größte Wahrscheinlichkeit be­sitzt, möglichst viele Fehler zu finden. Der erste Schritt in diese Richtung ist das Bilden von Äquivalenzklassen. Statt unzählig viele mögliche Faktorwerte zum Testen heranzuziehen, wird im einfachen Fall nur ein Faktorwert repräsentativ für alle Werte in der Äqui­valenz­klasse verwendet. In der folgenden Abbildung wurden zu jedem Faktor Äqui­valenzklassen und Testwerte hinzugefügt.

Abbildung in dieser Leseprobe nicht enthalten

Da Testfälle immer aus den Testdaten und dem erwarteten Ergebnis bestehen, wird ein wei­terer Faktor eingefügt, der das Ergebnis aus dem Methodenaufruf repräsentiert. Der Ergebnis­faktor ist immer ein Ausgangsfaktor. Dieser ist durch die entgegengesetzte Pfeilrichtung ge­kenn­zeichnet.

Abbildung in dieser Leseprobe nicht enthalten

Neben der manuellen Eingabe der Metainformationen können diese auch automatisiert erstellt werden. Aus dem eventuell vorliegenden Quelltext oder Assembly extrahiert TestIt die Klasse, Me­thoden und Faktoren automatisiert. In Testspezifikationen besteht die Möglichkeit, zu­sätz­lich Äquivalenzklassen und Testwerte anzugeben.

Die Spezifikation der Metainformationen sind somit komplett. Schritt 4 der Anleitung be­schreibt, wie aus den spezifizierten Faktorwerten Testfälle erstellt werden. Im Standardfall werden die Faktorwerte mit den anderen Faktorwerten kombiniert. Jedoch werden nur solche Faktor­werte kombiniert, deren Faktor dieselbe Richtung aufweist. Also Eingangsfaktoren werden nur mit anderen Eingangsfaktoren kombiniert. Dasselbe gilt für die Ausgangsfaktoren.

Pro Testfall und dessen Testdaten ist jeweils das erwartete Ergebnis anzugeben. Da nicht jeder Testfall in gleicher Weise geeignet ist, Fehler zu finden, kann man jeden einzelnen Test­fall aktivieren bzw. deaktivieren. Aus den bisher spezifizierten Metainformationen entstehen fol­gende vier Testfälle für die Methode Power:

Abbildung in dieser Leseprobe nicht enthalten

Somit sind die Testfälle komplett. Es handelt sich hierbei um ein sehr einfach gehaltenes Bei­spiel. Anspruchsvollere Beispiele mit ungültigen Testwerten und Spezialfällen finden Sie im Ab­schnitt Beispiele.

Jetzt fehlt noch der schrittweise Ablauf, wie diese Testfälle abgearbeitet werden. Mit diesem Thema beschäftigt sich der nächste Abschnitt.

4.2.2 Erzeugen des Testablaufs

Nachdem die Testfälle erstellt wurden, müssen diese zur Ausführung gebracht werden. Für die Ausgabe der Testfälle können Sie Quelltext-Vorlagen angeben, deren Platzhalter von TestIt später durch die Daten der einzelnen Testfälle ersetzt werden. Die Platzhalter sind dabei Textmarken, deren Name zwischen den Klammern <% und %> steht. Von TestIt sind be­reits einige Marken, wie beispielsweise <% Index %>, vorgegeben. Vorlagen sind jeweils einer Klasse bzw. den zu testenden Methoden zugeordnet. Sie bilden also das Gerüst für die Test­klasse bzw. einen Testfall. Nachfolgende Abbildung stellt diesen Vorgang grafisch dar.

Abbildung in dieser Leseprobe nicht enthalten

Der Aufbau einer Testmethode, wie zum Beispiel TestPower, folgt meist dem Schema:

1. Herstellen der Vorbedingungen: Erzeugen der Testdaten.
2. Test: Aufruf der zu testenden Methode.
3. Überprüfen der Nachbedingungen: Prüfen mittels Assertions, ob das erwartete mit dem tatsächlichen Ergebnis übereinstimmt.

Die Testmethode im unteren Teil der nachfolgenden Abbildung ist ebenfalls nach diesem Schema aufgebaut. Statt die Faktorwerte gesonderten Variablen zuzuweisen, könnten Sie direkt in den Methodenaufruf eingefügt werden. Diese längere Vorgehensweise soll ver­deut­lichen, dass das Herstellen der Vorbedingungen auch umfangreicher sein kann, wie es bei­spiels­weise beim Erstellen von Auflistungen der Fall ist.

Abbildung in dieser Leseprobe nicht enthalten

Um die Testklassen zu erstellen, werden die Vorlagen mittels Textersetzung an den Stellen der Marken zusammengefügt. Sämtliche Testmethoden kommen an die Stelle der Marke Methods, die Faktorwerte an die Stelle der Marke welche den Faktornamen trägt. Zusätzlich wird der Name der Testmethode mit einer laufenden Nummer an der Marke Index versehen. Falls mehrere Testfälle vorliegen, dient die Nummer zur Unterscheidung der einzelnen Test­me­tho­den. Eine Übersicht zu den verfügbaren Quelltext-Marken finden Sie in der Referenz.

Abbildung in dieser Leseprobe nicht enthalten

Das Beispiel hat gezeigt, dass es letztlich gleichgültig ist, welchen Text die Vorlage enthält. Der sehr simple Algorithmus ersetzt einfach die Marken mit Text. Die Semantik des Texts spielt für TestIt keine Rolle. Das Programm schränkt Sie daher nicht auf ein bestimmtes Test­frame­work oder eine Programmiersprache ein. Folglich ist es kein Problem statt einer Test­klasse einen HTML-Bericht zu erstellen. Die sich daraus ergebenden vielfältigen Möglich­keiten zeigen Ihnen die Beispiele in diesem Benutzerhandbuch.

Der folgende Abschnitt erläutert die Benutzeroberfläche von TestIt. Nach dem Durcharbeiten sind Sie in der Lage, die soeben gezeigten Schritte zur Erstellung der Tests praktisch um­zu­setzen.

4.3 Benutzeroberfläche

Im oberen Fensterbereich der Benutzeroberfläche von TestIt befinden sich die Menü- und Sym­bol­leiste. Mittels stichwortbezogener Hilfefunktion können Sie auf einfache Art und Weise eine Volltextsuche in den Hilfethemen durchführen. Die Statusleiste befindet sich im unteren Bereich des Fensters.

Der Arbeitsbereich von TestIt ist dreigeteilt. Links bzw. unten befindet sich jeweils ein Be­reich für andockbare Fenster. Insgesamt gibt es drei dieser Fenster:

- Klassenansicht: Zeigt hierarchisch die Metainformationen der zu testenden Klasse.
- Mitteilungen-Fenster: Während Sie arbeiten, informiert Sie TestIt über auf­ge­tre­tene Fehler.
- Ausgabe-Fenster: Zeigt den Standardausgabestrom der laufenden Tests.

Nachstehende Abbildung zeigt die Unterteilung des Hauptfensters:

Abbildung in dieser Leseprobe nicht enthalten

Wesentliche Eingabeelemente im primären Arbeitsbereich sind:

[...]

Ende der Leseprobe aus 125 Seiten

Details

Titel
Systematische Testfallgenerierung für den Black-Box-Test
Hochschule
Johannes Kepler Universität Linz  (Institut für Systemsoftware)
Note
Sehr gut
Autor
Jahr
2005
Seiten
125
Katalognummer
V42067
ISBN (eBook)
9783638401913
ISBN (Buch)
9783638680011
Dateigröße
1587 KB
Sprache
Deutsch
Schlagworte
Systematische, Testfallgenerierung, Black-Box-Test
Arbeit zitieren
Thomas Wetzlmaier (Autor), 2005, Systematische Testfallgenerierung für den Black-Box-Test, München, GRIN Verlag, https://www.grin.com/document/42067

Kommentare

  • Noch keine Kommentare.
Im eBook lesen
Titel: Systematische Testfallgenerierung für den Black-Box-Test



Ihre Arbeit hochladen

Ihre Hausarbeit / Abschlussarbeit:

- Publikation als eBook und Buch
- Hohes Honorar auf die Verkäufe
- Für Sie komplett kostenlos – mit ISBN
- Es dauert nur 5 Minuten
- Jede Arbeit findet Leser

Kostenlos Autor werden