Fachbereichsseminar - Fakultät Informatik/Mathematik

Werbung
Fachbereich Informatik/Mathematik
100. Fachbereichsseminar
Fehlersuche und Test von Software
1. Fehler und Fehlersuche in Programmen …
2. „Klassisches“ Testen (Jamus, JUnit)
3. Testen reaktiver und verteilter Systeme (EPKfix, SaxTester)
7. Februar 2005
Hartmut Fritzsche
1. Fehler und Fehlersuche in Programmen …
„Fehler“ - Abstraktionen:
Globale Sicht:
Ein Fehler ist jede Abweichung der tatsächlichen Ausprägung einer
Qualitätseigenschaft von der vorgesehenen Sollausprägung.
Korrektheit eines Programms:
Ein Fehler ist jede Abweichung
der Implikation von der Spezifikation (IEEE/ANSI-Standard).
Strukturelle Softwaretests:
Ein Fehler ist ein strukturelles Merkmal des Programmtextes, das ein
fehlerhaftes Verhalten des Programms verursacht.
Sprich: „Ein Programmfehler kann eine Programmausnahme (Exception) verursachen“.
„Durch Testen kann man die Anwesenheit von Fehlern zeigen, nicht aber deren Abwesenheit“
E.W. Dijkstra
2
Fehler aus der „Praxis“:
der Fehler, den ich zuletzt gesucht habe …
(Shell-Interpreter, LV BS, 3. Februar 2005)
der Fehler, an dem ich am längsten gesucht habe …
(im Garbage Collection, System TULISP, 1985)
ein wirklich komplizierter Fall …
(D. Knuth, „Man or Boy“, 1964)
3
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
int main(void) {
char buf[80];
pid_t pid;
int status;
ein simpler Shell-Interpreter:
das Klammerpaar ( ) wurde vergessen
• fork() erzeugt Sohnprozess, in dem wird
eingegebenes Kommando ausgeführt.
• im Vaterprozess ist (fälschlicherweise) der Wert
pid = 0 , da der Vergleichswert zugewiesen wird.
Auch hier wird das eingelesene Kommando
ausgeführt, waitpid wird nie erreicht.
printf("%% ");
while(fgets(buf,80, stdin) != NULL) {
buf[strlen(buf) - 1] = 0;
if ( (pid = fork()) < 0)
printf("fork error");
else if (pid == 0) {
execlp(buf, buf, (char *) 0);
printf("command not executable: %s\n ",buf);
exit(127);
}
if ((pid = waitpid(pid, &status, 0)) < 0)
printf("waitpid error");
printf("%% ");
}
exit(0);
/* exit(4) */
}
4
hartmut@linux:~/BSII> ./a.out
% date
Sam Feb 5 18:11:01 CET 2005
Sam Feb 5 18:11:01 CET 2005
hartmut@linux:~/BSII> echo $?
0
hartmut@linux:~/BSII>
Analyse:
• Fehler ohne Testwerkzeug ermittelt
• keine Spezifikation vorhanden
• manuelle Pfadanalyse (Parallelität)
hartmut@linux:~/BSII> ./a.out
% date
Sam Feb 5 18:11:57 CET 2005
% ps
PID TTY
TIME CMD
2372 pts/1
00:00:00 bash
2665 pts/1
00:00:00 a.out
2667 pts/1
00:00:00 ps
% hartmut@linux:~/BSII>
5
TULISP
Garbage Collection:
mark + sweep
• typenreine Seiten – hier: pair
• automatisch ausgelöstes GC
Wirkung des Fehlers:
In Listen tauchen falsche
Elemente auf:
1 falsch verkettetes Element auf ca.
15000 richtig verkettete
(keine Exception !)
Analyse:
• Es kann kein Testfall konstruiert
werden, um den Fehler zu
reproduzieren!
• keine Spezifikation vorhanden
• kein Testwerkzeug verfügbar
• Fehlersuche mit Debugger
6
1 Zelle „pair“
1 Page
→ 1 Halbwort (4 Hex)
→ 1020 Halbworte
≈ 15 Seiten
→ 15300 Zellen
81E 1
7
„Man or Boy“ ?
oder: Wen interessiert noch die Parametervermittlung „call-by-name“?
(Testprogramm für Algol-60-Compiler von D. Knuth, 1964)
begin real procedure A(k,x1,x2,x3,x4,x5);
value k; integer k;
Prozedur B ist lokal zu A
begin real procedure B;
begin
B wird an A übergeben
k via call-by-value
k := k - 1;
B := A := A(k,B,x1,x2,x3,x4)
end;
if k <= 0 then A := x4 + x5 else B
end;
outreal(A(10,1,-1,-1,1,0))
end;
Prozeduraufrufe
8
Ergebnisse bis k=23:
>> ManOrBoyEnv
1
0
-2
0
Scheme (Ein LISP-Dialekt mit lexikaler Bindung):
1
0
1
-1
(define A (lambda(k x1 x2 x3 x4 x5)
-10
(letrec ((B (lambda()
-30
(set! K (- k 1))
-67
(A k B x1 x2 x3 x4))))
-138
(if (<= k 0)(+ (x4)(x5))(B)))))
-291
-642
-1446
Aufruf:
-3250
-7244
(A 10 (lambda() 1)(lambda() -1)(lambda() -1)
-16065
(lambda() 1)(lambda() 0))
-35601
-78985
-175416
-389695
-865609
Referenz: H. Fritzsche, I.O. Kerner / Informatik-Spektrum 20/3 1997
-1922362
9
2. „Klassisches“ Testen
Quellprogramm
(verschiedene
Quellsprachen)
(Jamus, JUnit)
Syntaxbaum
Zielprogramm
(verschiedene
Objektsprachen)
Der Syntaxbaum ist die Referenz-Struktur eines Programms (nicht das Quellprogramm!)
10
2. „Klassisches“ Testen
(Jamus, JUnit)
Test-Runner
Quellprogramm
Syntaxbaum
(verschiedene
Objektsprachen)
(verschiedene
Quellsprachen)
Steuerflussgraph
Visualisierung
Zielprogramm
Testrahmen
(Testcases)
11
3. Testen reaktiver und verteilter Systeme …
Systeme
Transformative Systeme
Reaktive Systeme
„prozedural“, berechnen
Ausgangsdaten,
„offen“, reagieren auf ständig
eintreffende Eingangsdaten,
Eingangsdaten stehen zum
Zeitpunkt der Aktivierung des
Systems bereit
das Bewegen durch einen
Zustandsraum erfolgt
ereignisgetrieben
( Hardware oder Software,
Klimaanlage, BS, EPK, … )
12
Anforderungsanalyse
Formale
Spezifikation
BMBF Verbundprojekt EPK-fix,1995 -98
„Testassistenzsystem“ TASSI
Generierung
13
TASSI
• automatische und interaktive
Testung
• Testmonitor mit GUI
• parametrisierte Teststrategien
• Capture – Replay – Funktion
• Browswn in Fehlerklassifikationen
• Automatisches Prüfen
Formalisierter Design-Richtlinien
Testen ist ein Verfahren mit
Stichprobencharakter!
→
Testendekriterium
14
Nutzung von Beweistechniken (z.B.
SLD-/FWD-Resolution)
Verifikation:
Ziel eines Beweisvorganges ist es, nachzuweisen, dass die Software
eine gegebene formale Spezifikation erfüllt (partielle bzw. totale Korrektheit).
A if B and C and …
A :- B, C, … .
Wir drehen die Zielfunktion um:
Beim Testen reaktiver Systeme ist es das Ziel, in erreichten
Systemzuständen durch Beweise Fehler gegenüber formal
spezifizierten Sachverhalten aufzudecken.
„Es ist ein Fehler“ if B and C and … .
Beispiel: Formale Überprüfung von Design-Richtlinien
Es ist ein Fehler, wenn ein Objekt mit einer Hintergrundfarbe
transitiv ein Element mit einer identischen Fontfarbe enthält
15
Beispiel: SaxTester (2003)
Technologies & Application Development
Testen verteilter (Web-) Anwendungen mit GUIs
Kommunikation mittels XML-RPC
Capure – Replay – Funktionalität
Automatisches/manuelles Erstellen und Abspielen von Python-Skripts
Testung von Browser-Inhalten (MS IE) über das
Component Object Model (COM-Schnittstelle)
(Diplomarbeit D. Linke, HTWD 2004, Medieninformatik)
16
Symbolic Model Checking
Aussagen über erreichte oder zu erwartende Zustände
eines Systems werden mit (temporal-) logischen Formeln
beschrieben (z.B. Computational Tree Logic).
Ein Model-Checker prüft Formeln gegenüber dem Modell.
AX f :
AG f :
In jedem unmittelbaren Nachfolgezustand des aktuellen
Zustands ist f erfüllt.
Entlang jedes Pfades wird f in jedem Zustand erfüllt.
Beispiel: Klimaanlage
AG((Running & AboveDesiredTemp) → (AC | AX(AC)))
AG((Running & BelowDesiredTemp) → (HEAT | AX(HEAT)))
17
Resümee
•
Praktisch werden kaum formale Spezifikationen (z.B. Klassen-Invarianten)
unabhängig vom Programmtext verwendet.
•
Entwicklungswerkzeuge (z.B. Together ControlCenter) verbinden
Spezifikationen mit Generierung (Syntaxbaum!) und Reverse Engineering.
•
Testwerkzeuge entlasten bisher den Programmierer nicht davon, Testfälle zu
beschreiben, und werden es auch künftig nur begrenzt tun.
Testfallbeschreibungen sind Spezifikationen!
•
Testen reaktiver, verteilter Systeme wird praktisch noch zu wenig unterstützt.
Ansätze existieren für einzelne Programmiermodelle (z.B. COM)
18
Herunterladen