Software-Qualität - Hochschule Osnabrück

Werbung
Software-Qualität
Prof. Dr. Stephan Kleuker
Hochschule Osnabrück
Software-Qualität
Stephan Kleuker
1
Ich
• Prof. Dr. Stephan Kleuker, geboren 1967, verheiratet, 2
Kinder
• seit 1.9.09 an der FH, Professur für Software-Entwicklung
• vorher 4 Jahre FH Wiesbaden
• davor 3 Jahre an der privaten FH Nordakademie in Elmshorn
• davor 4 ½ Jahre tätig als Systemanalytiker und
Systemberater in Wilhelmshaven
• [email protected], Raum SI 0109
Software-Qualität
Stephan Kleuker
2
Ablauf
• 2h Vorlesung + 2h Praktikum = 5 CP
• Praktikum :
– Anwesenheit = (Übungsblatt vorliegen + Lösungsversuche
zum vorherigen Aufgabenblatt)
– Übungsblätter mit Punkten (Σ ≥ 100), zwei/drei Studis
– Praktikumsteil mit 80 oder mehr Punkten bestanden
• Prüfung: Projektaufgabe (Kenntnisse aus der Vorlesung
anwenden und/oder eigene Untersuchungen)
• Folienveranstaltungen sind schnell, bremsen Sie mit Fragen
• von Studierenden wird hoher Anteil an Eigenarbeit erwartet
Software-Qualität
Stephan Kleuker
3
Verhaltenscodex
•
•
•
•
Rechner sind zu Beginn der Veranstaltung aus
Handys sind aus
Wir sind pünktlich
Es redet nur eine Person zur Zeit
• Sie haben die Folien zur Kommentierung in der Vorlesung
vorliegen, zwei Tage vor VL abends mit Aufgaben im Netz,
Aufgabenzettel liegen in der Übung vor (Ihre Aufgabe)
http://
http://www.edvsz.hs
://www.edvsz.hswww.edvsz.hs-osnabrueck.de/skleuker/index.html
• Probleme sofort melden
• Wer aussteigt, teilt mit, warum
Software-Qualität
Stephan Kleuker
4
Grundvoraussetzungen
Gute Programmierkenntnisse in C++
• Klasse
• Methode
• Klassenvariable und Klassenmethode
• Sichtbarkeit
• Vererbung
• abstrakte Klassen
• Collections (z. B. Liste, Menge)
• Polymorphie
• schön: Java-Erfahrungen
Software-Qualität
Stephan Kleuker
5
Ziele
• Verfahren zur Qualitätssicherung (QS) kennen lernen,
anwenden lernen, situationsabhängig bewerten lernen
• Prozess zur systematischen QS kennen und nutzen lernen
• Umgang und selbständige Einarbeitung in
Beispielwerkzeuge
• Fehler kennenlernen und bei eigenen Entwicklungen
vermeiden
Randbedingungen
• Programmierung in Java (Erkenntnisse übertragbar auf
andere Sprachen)
• Open Source Werkzeuge
• keine Software-Ergonomie (-> BOSE)
Software-Qualität
Stephan Kleuker
6
Themengebiete (Planung)
1 Fehlerquellen von Software
2 Unit - Tests
3 Äquivalenzklassentests
4 Überdeckungstests
5 Mocking
6 Test von Software mit grafischen Nutzungsoberflächen
7 Performance und Speicherauslastung
8 Testautomatisierung
9 Metriken
10 Konstruktive Qualitätssicherung
11 Organisation des QS-Prozesses in IT-Projekten
Software-Qualität
Stephan Kleuker
7
Literatur
• http://home.edvsz.hsosnabrueck.de/skleuker/CSI/index.html
• Peter Liggesmeyer, Software-Qualität:
Testen, Analysieren und Verifizieren
von Software, Spektrum Akademischer
Verlag, 2. Auflage, 2009
• Stephan Kleuker, Grundkurs SoftwareEngineering mit UML, Kapitel 11,
Vieweg+Teubner, 2. Auflage, 2010
Software-Qualität
Stephan Kleuker
8
1. Fehlerquellen von Software
•
•
•
•
•
•
•
Software-Fehler und ihre dramatischen Folgen
Typische Entwicklungsphasen von Software
Fehler in der Anforderungsanalyse
Fehler im Design
Fehler bei der Implementierung
Fehler bei der Qualitätssicherung
Fehler im Projektumfeld
Software-Qualität
Stephan Kleuker
9
Sammlung
• An welche Fehler, die mit Software zusammenhängen
erinnern Sie sich?
Software-Qualität
Stephan Kleuker
10
Beispiele markanter Software-Fehler (1/2)
1962
1971
1982
1982
1991
1992
1994
1993
1995
Trägerrakete Mariner 1, Selbstzerstörung nach Kursabweichung; in
SW ein Komma statt eines Punktes
Eole 1, Satellit zur Steuerung von Wetterballons, 71 Ballons
bekommen irrtümlich Befehl zur Selbstzerstörung
Größte nicht-nukleare Explosion durch Fehler in Steuerungs-SW einer
russischen Gap-Pipeline
Flugabwehrsystem der Fregatte Sheffield versagt; anfliegender
argentinischer Flugkörper als Freund erkannt
Flugabwehrsystem Patriot verfehlt Scud-Rakete; notwendiger
Systemneustart nach max. 100 h vergessen
Londoner Ambulance Service, neue SW führt zu Wartezeiten von bis
zu drei Stunden
Mondsonde Clementine, Sonde sollte einen Asteroiden ansteuern,
durch einen Software-Fehler wurden die Triebwerke nach der
Kurskorrektur nicht mehr abgestellt
Pentium-Chip, fehlerhafte Divisionsberechnung
Automatischer Gepäcktransport im Flughafen Denver funktioniert
nicht; zu viele Informationen im Netz
Software-Qualität
Stephan Kleuker
11
Beispiele markanter Software-Fehler (2/2)
1996
1999
2001
2002
2003
2003
2004
2005
2005
2005
2005
Notwendige Selbstzerstörung der Ariane 5; falsche Steuersignale
durch SW-Übernahme von Ariane 4
Fehlende Sturmwarnung für Süddeutschland, da SW starken
Druckabfall als Messfehler interpretierte
Fehlerhafte Bestrahlung von Krebspatienten durch nicht bedachten
Bedienfehler
Amerikanische Bomben schlagen wg. SW-Fehler 15 bis 250 m zu weit
links ein
Patriot schießt befreundetes englisches Flugzeug ab
Stromausfall USA, falsche Reaktion in SW auf starke
Lastschwankungen im Netz
Rückruf Mercedes-Transporter, Fehler in Steuerungs-SW schalten
evtl. Motor ab (auch andere Fahrzeughersteller)
Arbeitslosengeld (ALG 2): Berechnungsfehler führt zur Nichtzahlung
von Krankenkassenbeiträgen
ALG 2: keine Auszahlung bei neun-stelliger Kontonummer
T-Mobile: SMS für 80 statt 19 Cent abgerechnet
Russische Trägerrakete Cryosat; Signal zum Abschalten der
Triebwerke der zweiten Stufe nicht weiter geleitet
Software-Qualität
Stephan Kleuker
12
Historie der Software-Entwicklung
• erste Computer von Spezialisten mit sehr hohem
Bildungsniveau entwickelt und programmiert
• Computer und Programme waren Individualleistungen
• Mit steigender Verfügbarkeit von Computern stieg auch die
Anzahl der SW- und HW-Fehler
• Software-Entwicklung ist hoch kreativer (künstlerischer)
Prozess, der mit der Zeit in einen ingenieurwissenschaftlichen Rahmen (Software-Engineering)
eingebettet wurde
• Zentrale Ergebnisse: Vorgehensmodelle mit
Prozessmodellen (wer macht wann, was, mit wem, mit
welchen Hilfsmitteln, warum)
Software-Qualität
Stephan Kleuker
13
Skizze eines Vorgehensmodells
Anforderungsanalyse
Grobdesign
Feindesign
Implementierung
Test und Integration
Bsp.: vier Inkremente
Software-Qualität
Merkmal:
Projekt in kleine Teilschritte zerlegt,
n+1-ter Schritt kann Probleme des nten Schritts lösen
Vorteile:
- dynamische Reaktion auf Risiken
- Teilergebnisse mit Kunden
diskutierbar
mögliche Nachteile:
- schwierige Projektplanung
- schwierige Vertragssituation
- Kunde erwartet zu schnell
Endergebnis
Stephan Kleuker
14
Qualitätssicherung (1/2)
Anforderungsanalyse
Feindesign
Implementierung
Qualitätssicherung (QS)
Grobdesign
Test und Integration
Software-Qualität
Stephan Kleuker
• QS ist eigenständiges
Teilprojekt
• zu jedem Projekt gehört
ein QS-Plan
• QS Plan: was wird wann
von wem wie überprüft
• QS unabhängig vom
Projekt organisiert
• Form der QS sehr stark
projektabhängig
• häufig Forderung nach
Normen (z.B. ISO 9000)
und QS-Standards (z.B
DO 178B)
15
Qualitätssicherung (2/2)
konstruktive Qualitätssicherung:
• QS vor Projekt planen
• Auswahl von Methoden, Werkzeugen, Prozessen,
Schulungen
• Normen, Guidelines und Styleguides
analytische Qualitätssicherung:
• manuelle Verfahren (z.B: Inspektion und Audit) zur Prüfung
der Einhaltung konstruktiver Ansätze
• Reviews von Teilprodukten (z.B. Anforderungen, Design)
• Einsatz von Testverfahren (Äquivalenzklassen,
Überdeckungen) in unterschiedlichen Testphasen
(Entwicklertests, Integrationstests, Systemtests,
Abnahmetests)
Software-Qualität
Stephan Kleuker
16
Typische Fehler der Anforderungsanalyse
• Kunde wird zu wenig in Planungen eingebunden
• Kunde versteht Analysedokumente der IT nicht; nickt sie
trotzdem ab
• Rahmenbedingungen (HW, umgebende SW) nicht geklärt
• Stakeholder (in irgendeiner Form Projektbetroffene) nicht in
Analyse involviert (z. B. Endnutzer vergessen)
• Analyse der vom Kunden genutzten SW nicht durchgeführt;
z. B. Look-and-Feel an branchenüblicher Software
orientieren
• Grundregel für IT-Projekte: Garbage in - Garbage out
Software-Qualität
Stephan Kleuker
17
Typische Fehler des Designs
• keine Prüfung, ob genau die Anforderungen umgesetzt
werden
• Design-Entscheidungen werden nicht dokumentiert (UML:
Aktivitätsdiagramme, Klassendiagramme,
Zustandsdiagramme, Sequenzdiagramme)
• mangelndes Design-Know-how macht resultierende
Software langfristig unwartbar, nicht erweiterbar
• Randbedingungen z. B. der HW nicht berücksichtigt
(Performance, Kommunikationsprotokolle, ...)
Software-Qualität
Stephan Kleuker
18
Typische Fehler der Implementierung
• Laufendes Programm – unerwünschte Funktionalität
– Spezifikation war missverständlich
– Überflüssige Goldrandlösung
• Mögliche Alternativen werden vergessen
• Programme zu komplex zum Testen (Schachteln von if,
while, switch)
• Programm bei Wiederverwendung/Erweiterung unwartbar
(versteckte Konstanten, versteckte Abhängigkeiten)
• Existierende Lösungen missachtet
• Kein Gedanke an Laufzeit
Software-Qualität
Stephan Kleuker
19
Typische Fehler der Qualitätssicherung
• alle Tests werden von den Entwicklern durchgeführt
• Fehlermöglichkeiten vergessen
• Testfälle können nicht nachvollzogen oder wiederholt
werden; mangelnde Dokumentation der Testfälle
• Anforderungen nicht konsequent in Testfälle umgesetzt
• fehlende Werkzeuge zur Testautomatisierung; manuelle
Tests zu zeitaufwändig
• Testumgebung passt nicht zur realen Zielumgebung des
Kunden
• Informationen zum Performance- und Lastverhalten
angeschlossener Systeme nicht berücksichtigt
Software-Qualität
Stephan Kleuker
20
Typische Fehler in der Projektorganisation
• Kunde wird zu selten über Projektstand informiert
• Kunde will vor Fertigstellung der Software „nicht belästigt“
werden
• Der Umgang mit Änderungswünschen des Kunden und des
Auftragnehmers ist unterspezifiziert
• Auftragnehmer wird über projektrelevante Änderungen
beim Kunden nicht informiert
• kein Risikomanagement (beim Auftragnehmer und beim
Kunden)
Software-Qualität
Stephan Kleuker
21
Schleichende Software-Fehler - Beispiel
• kleines Unternehmen geht mit viel Know-how und neuer
Individual-SW auf den Markt
• SW wird bei Kunden direkt vor Ort angepasst
• mit Kundenzahl wächst Zahl der Anpassungen und weiterer
Kundenwünsche
• dadurch, dass zentrale Daten mehrfach in Modulen
gehalten werden, Datenabhängigkeiten schwer analysierbar
sind und Individual-SW nicht dokumentiert ist, wird SW
unwartbar
• typisches Problem vieler SW-Systeme: am Anfang
erfolgreich werden sie irgendwann nicht mehr
weiterentwickelbar
Software-Qualität
Stephan Kleuker
22
Ursachen für Software-Fehler
• mangelndes Verständnis von Anforderungen
• Übersehen von Ablaufmöglichkeiten
• Programmierfehler
• zu wenig Zeit für Tests
• mangelnde Qualifikation der Mitarbeiter
• unpassende SW-Werkzeuge
• mangelndes Managementverständnis für IT-Entwicklung
• hoher Kostendruck, starker Preiskampf
Software-Qualität
Stephan Kleuker
23
Teufelsquadrat für IT-Projekte (Sneed)
Qualität
Funktionalität
+
+
+ +
Kosten
-
Zeit
• Konzentration auf ein Ziel benötigt bei gleichen
Rahmenbedingungen Vernachlässigung mindestens eines
anderen Ziels (Fläche bleibt identisch)
• generelle Verbesserung nur durch Verbesserung der
Rahmenbedingungen (z.B. der Prozesse)
Software-Qualität
Stephan Kleuker
24
Qualitätssicherung
• Qualitätssicherung (allgemein)
Alle geplanten und systematischen Tätigkeiten, die
notwendig sind, um ein angemessenes Vertrauen zu
schaffen, dass ein Produkt oder eine Dienstleistung die
gegebenen Qualitätsanforderungen erfüllt
• Qualitätssicherung (softwarespezifisch)
Die Gesamtheit aller Maßnahmen und Hilfsmittel, die mit
dem Ziel eingesetzt werden, die gestellten Anforderungen
an den Entwicklungs- und Wartungsprozess sowie an das
Softwareprodukt zu erreichen
aus DIN 55350-11: Begriffe zu Qualitätsmanagement und
Statistik, Teil 11, 8/95
Software-Qualität
Stephan Kleuker
25
Aufwand für analytische Qualitätssicherung
C. Jones, Applied Software Measurement, 1991
Software-Qualität
Stephan Kleuker
26
Wann werden Fehler gefunden?
K.-H. Möller, Ausgangsdaten für Qualitätsmetriken, 1996
Software-Qualität
Stephan Kleuker
27
Prinzip der integrierten Qualitätsprüfung [Lig]
Analyse
Prüfungen durch Werkzeug
Inspektion der Ergebnisse
ok
nicht ok
Entwurf
Prüfungen durch Werkzeug
Inspektion der Ergebnisse
ok
nicht ok
Kodierung
nicht ok
Software-Qualität
Prüfungen durch Compiler
Modul-, Integrations-, ...tests
...
Stephan Kleuker
28
Definitionen (1/2) [Lig]
• Qualität (DIN 55350-11) definiert als „Beschaffenheit einer
Einheit bezüglich ihrer Eignung, festgelegte und abgeleitete
Erfordernisse (Qualitätsanforderungen) zu erfüllen“
• Qualitätsanforderung: Gesamtheit der Einzelanforderungen
an eine Einheit, die die Beschaffenheit dieser Einheit
betreffen
• Qualitätsmerkmal: Die konkrete Beurteilung von Qualität
geschieht durch so genannte Qualitätsmerkmale. Diese
stellen Eigenschaften einer Funktionseinheit dar, anhand
derer ihre Qualität beschrieben und beurteilt wird, die
jedoch keine Aussage über den Grad der Ausprägung
enthalten. Ein Qualitätsmerkmal kann über mehrere Stufen
in Teilmerkmalen verfeinert werden.
Software-Qualität
Stephan Kleuker
29
Definitionen (2/2) [Lig]
• Qualitätsmaß: konkrete Ausprägung eines
Qualitätsmerkmals geschieht durch so genannte
Qualitätsmaße; dies sind Maße, die Rückschlüsse auf die
Ausprägung bestimmter Qualitätsmerkmale zulassen
(Beispiel: Durchschnittliche Antwortzeit für
Laufzeiteffizienz)
• Fehlverhalten oder Ausfall (failure) zeigt sich dynamisch bei
der Benutzung eines Produkts, beim dynamischen Test einer
SW erkennt man keine Fehler, sondern Fehlverhalten bzw.
Ausfälle.
• Fehler oder Defekt (fault, defect) ist bei SW die statisch im
Programmcode vorhandene Ursache eines Fehlverhaltens
oder Ausfalls
Software-Qualität
Stephan Kleuker
30
Qualitätsmerkmale
funktional
• Korrektheit
nicht funktional
• Sicherheit
• Zuverlässigkeit
• Verfügbarkeit
• Robustheit
• Speicher- und Laufzeiteffizienz
• Änderbarkeit
• Portierbarkeit
• Prüfbarkeit
• Benutzbarkeit
Anmerkung: Qualitätsmerkmale können Wechselwirkungen haben
Software-Qualität
Stephan Kleuker
31
2. Unit - Tests
•
•
•
•
•
Annotationen
Varianten von JUnit
Testfälle mit JUnit
Testsuite mit JUnit
Parametrisierte Tests
• Warnung für dieses und die weiteren Kapitel:
Der Programmcode ist meist ein Beispiel für schlechte
Formatierung; hier erlaubt, um möglichst viele Details auf
einer Folie mit Ihnen zu diskutieren
Software-Qualität
Stephan Kleuker
32
Testfall
• Vor dem Testen müssen Testfälle spezifiziert werden
• Vorbedingungen
– Zu testende Software in klar definierte Ausgangslage bringen
(z. B. Objekte mit zu testenden Methoden erzeugen)
– Angeschlossene Systeme in definierten Zustand bringen
– Weitere Rahmenbedingungen sichern (z. B. HW)
• Ausführung
– Was muss wann gemacht werden (einfachster Fall:
Methodenaufruf)
• Nachbedingungen
– Welche Ergebnisse sollen vorliegen (einfachster Fall:
Rückgabewerte)
– Zustände anderer Objekte / angeschlossener Systeme
Software-Qualität
Stephan Kleuker
33
JUnit
• Framework, um den Unit-Test eines Java-Programms zu
automatisieren
• einfacher Aufbau
• leicht erlernbar
• geht auf SUnit
(Smalltalk) zurück
• mittlerweile für
viele Sprachen
verfügbar (NUnit,
CPPUnit)
Software-Qualität
Stephan Kleuker
34
JUnit - zwei Varianten
JUnit 3.8.x
• entwickelt für „klassisches“ Java vor Java 5
• Testklassen müssen von einer Klasse TestCase erben
• Tests müssen in Testklassen stehen
• gibt einige weitere QS-Werkzeuge, die solche Tests nutzen
bzw. selbst erstellen (gehen nicht mit JUnit 4)
• Ideen leichter auf XUnit-Varianten übertragbar
JUnit 4.x
• nutzt Annotationen
• Tests können in zu testenden Klassen stehen
• etwas flexibler als JUnit 3.8.x
Software-Qualität
Stephan Kleuker
35
Einsatz von Annotationen: Weiterverarbeitung
// HelloWorldService.java
import javax.jws.WebMethod;
import javax.jws.WebService;
@WebService
public class HelloWorldService {
@WebMethod
public String helloWorld() {
return "Hello World!";
}
}
• Annotationen beginnen mit einem @ und können, z. B. von
anderen Programmen, zur Weiterverarbeitung genutzt werden
• hier z. B. soll die Erzeugung eines Web-Services durch die
Kennzeichnung relevanter Teile durch Annotationen erfolgen
• Java besitzt seit Version 5 Annotationen, man kann selbst
weitere definieren
Software-Qualität
Stephan Kleuker
36
Syntax von Annotationen
• Annotationen können Parameter haben
• ohne Parameter: @EinfacheAnnotation
• mit einem Parameter @EinAnno(par="Hallo")
EinAnno(par="Hallo") oder
@EinAnno("Hallo")
EinAnno("Hallo") (bei nur einem Parameter kann der
Parametername weggelassen werden)
• mit mehreren Parametern werden Wertepaare
(Parametername, Wert) angegeben
@KomplexAnno(par1="Hi",
KomplexAnno(par1="Hi", par2=42, par3={41,43})
• Annotationen können bei/vor anderen Modifiern (z.B.
public, abstract) bei folgenden Elementen stehen:
− Exemplar- und Klassenvariable
– package
– class, interface, enum − lokale Variablen
− Parameter
– Methode
• Man kann einschränken, wo welche Annotation erlaubt ist
Software-Qualität
Stephan Kleuker
37
Beispiel: Nutzung vordefinierter Annotation
public class Oben {
public void supertolleSpezialmethode(){
System.out.println("Ich bin oben");
}
}
public class Unten extends Oben{
@Override public void superTolleSpezialmethode(){
System.out.println("Ich bin unten");
}
public static void main(String[] s){
Unten u = new Unten();
u.supertolleSpezialmethode();
}
ohne Annotation in Java 1.4:
}
Ich bin oben
Compilermeldung:
..\
..\..\
..\netbeans\
netbeans\Annotationen\
Annotationen\src\
src\Unten.java:2: method does not
override a method from its superclass
@Override public void superTolleSpezialmethode(){
1 error
Software-Qualität
Stephan Kleuker
38
Konstruktiver Ansatz
• Testfälle werden in Java programmiert, keine spezielle
Skriptsprache notwendig
• Idee ist inkrementeller Aufbau der Testfälle parallel zur
Entwicklung
– Pro Klasse wird mindestens eine Test-Klasse
implementiert (oder in Klasse ergänzt)
• JUnit ist in Eclipse integriert, sonst muss das Paket junit.jar
zu CLASSPATH hinzugefügt werden.
Software-Qualität
Stephan Kleuker
39
Spezifikationsausschnitt
• Gegeben sei eine Aufzählung mit den folgenden Werten
package verwaltung.mitarbeiter;
public enum Fachgebiet {
ANALYSE, DESIGN, JAVA, C, TEST
}
• Zu entwickeln ist eine Klasse Mitarbeiter, wobei jedes
Mitarbeiterobjekt
– eine eindeutige Kennzeichnung (id) hat
– einen änderbaren Vornamen haben kann
– einen änderbaren Nachnamen mit mindestens zwei Zeichen
hat
– eine Informationssammlung mit maximal drei Fachgebieten
hat, die ergänzt und gelöscht werden können
Software-Qualität
Stephan Kleuker
40
Klasse Mitarbeiter (1/4) - fast korrekt
package verwaltung.mitarbeiter;
import java.util.HashSet;
import java.util.Set;
public class Mitarbeiter {
private int id;
private static int idGenerator = 100;
private String vorname;
private String nachname;
private Set<Fachgebiet> fachgebiete;
public Mitarbeiter(String vorname, String nachname) {
if (nachname == null || nachname.length() < 2)
throw new IllegalArgumentException(
"Nachname mit mindestens zwei Zeichen");
this.vorname = vorname;
this.nachname = nachname;
this.id = idGenerator++;
this.fachgebiete = new HashSet<Fachgebiet>();
} Software-Qualität
Stephan Kleuker
41
Klasse Mitarbeiter (2/4)
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getVorname() { return vorname; }
public void setVorname(String vorname) {
this.vorname = vorname; }
public String getNachname() { return nachname; }
public void setNachname(String nachname) {
this.nachname = nachname;}
public Set<Fachgebiet> getFachgebiete() {
return fachgebiete;}
public void setFachgebiete(Set<Fachgebiet> fachgebiete) {
this.fachgebiete = fachgebiete;
}
Software-Qualität
Stephan Kleuker
42
Klasse Mitarbeiter (3/4)
public void addFachgebiet(Fachgebiet f){
fachgebiete.add(f);
if(fachgebiete.size() > 3){
fachgebiete.remove(f);
throw new IllegalArgumentException(
"Maximal 3 Fachgebiete");
}
}
public void removeFachgebiet(Fachgebiet f){
fachgebiete.remove(f);
}
public boolean hatFachgebiet(Fachgebiet f){
return fachgebiete.contains(f);
}
Software-Qualität
Stephan Kleuker
43
Klasse Mitarbeiter (4/4)
@Override
public int hashCode() { return id; }
@Override
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass())
return false;
Mitarbeiter other = (Mitarbeiter) obj;
return (id == other.id);
}
@Override
public String toString(){
StringBuffer erg = new StringBuffer(vorname+
" "+nachname+" ("+id+")[ ");
for(Fachgebiet f:fachgebiete)
erg.append(f+" ");
erg.append("]");
return erg.toString();
Stephan Kleuker
} Software-Qualität
44
Testen von Hand
public static void main(String... s){
Mitarbeiter m = new Mitarbeiter("Uwe","Mey");
m.addFachgebiet(Fachgebiet.ANALYSE);
m.addFachgebiet(Fachgebiet.C);
m.addFachgebiet(Fachgebiet.JAVA);
System.out.println(m);
m.addFachgebiet(Fachgebiet.TEST);
}
Uwe Mey (100)[ C JAVA ANALYSE ]
Exception in thread "main"
java.lang.IllegalArgumentException: Maximal 3 Fachgebiete
at
verwaltung.mitarbeiter.Mitarbeiter.addFachgebiet(Mitarbei
ter.java:58) at
verwaltung.mitarbeiter.Mitarbeiter.main(Mitarbeiter.java:
99)
Software-Qualität
Stephan Kleuker
45
Anlegen einer Testklasse (1/2)
Software-Qualität
Stephan Kleuker
46
Anlegen einer Testklasse (2/2)
Software-Qualität
Stephan Kleuker
47
Testen mit JUnit
• Tests werden mit Methoden durchgeführt, die mit
Annotation @Test markiert sind
• Testmethoden haben typischerweise keinen Rückgabewert
(nicht verboten)
• Tests stehen typischerweise in eigener Klasse; für Klasse X
eine Testklasse XTest (können auch in zu testender Klasse
stehen)
• Mit Klassenmethoden der Klasse Assert werden gewünschte
Eigenschaften geprüft
Assert.assertTrue("korrekter Vorname"
,m.getVorname().equals("Ute"));
• JUnit steuert Testausführung, Verstöße bei Prüfungen
werden protokolliert
Software-Qualität
Stephan Kleuker
48
Test des Konstruktors und der eindeutigen Id
package verwaltung.mitarbeiter;
import org.junit.Assert;
import org.junit.Test;
public class MitarbeiterTest {
@Test
public void testKonstruktor(){
Mitarbeiter m = new Mitarbeiter("Ute","Mai");
Assert.assertTrue("korrekter Vorname"
,m.getVorname().equals("Ute"));
Assert.assertTrue("korrekter Nachname"
,m.getNachname().equals("Mai"));
}
@Test
public void testEindeutigeId(){
Assert.assertTrue("unterschiedliche ID"
, new Mitarbeiter("Ute","Mai").getId()
!= new Mitarbeiter("Ute","Mai").getId());
}
Software-Qualität
Stephan Kleuker
49
Anmerkungen
• keine gute Idee: mehrere Asserts hintereinander (scheitert
das Erste, wird Zweite nicht betrachtet -> Tests trennen)
• Assert-Methoden haben optionalen ersten String-Parameter
• String kann genauere Informationen über erwartete Werte
enthalten, z. B. über toString-Methoden der beteiligten
Objekte
• generell reicht Assert.assertTrue()
Assert.assertTrue() aus, gibt viele weitere
Methoden
• Um nicht immer die Klasse Assert vor Methoden angeben zu
müssen, kann man auch (persönlich unschön) folgendes
nutzen:
import static org.junit.Assert.*;
org.junit.Assert.*;
Software-Qualität
Stephan Kleuker
50
Ausschnitt: Klassenmethoden von Assert
assertArrayEquals(java.lang.Object[]
assertArrayEquals(java.lang.Object[] expecteds,
java.lang.Object[] actuals)
Asserts that two object arrays are equal.
assertEquals(double
assertEquals(double expected, double actual, double delta)
Asserts that two doubles or floats are equal to within
a positive delta.
assertFalse(boolean
assertFalse(boolean condition)
assertNotNull(java.lang.Object
assertNotNull(java.lang.Object object)
assertNull(java.lang.Object
assertNull(java.lang.Object object)
assertSame(java.lang.Object
assertSame(java.lang.Object expected,
java.lang.Object actual)
Asserts that two objects refer to the same object.
assertThat(T
assertThat(T actual, org.hamcrest.Matcher<T> matcher)
Asserts that actual satisfies the condition specified
by matcher.
assertTrue(boolean
assertTrue(boolean condition)
fail()
Fails a test with no message.
fail()
Software-Qualität
Stephan Kleuker
51
Test-Fixture
• Testfall sieht in der Regel so aus, dass eine bestimmte
Konfiguration von Objekten aufgebaut wird, gegen die der
Test läuft
• Menge von Testobjekten wird als Test-Fixture bezeichnet
• Damit fehlerhafte Testfälle nicht andere Testfälle
beeinflussen können, wird die Test-Fixture für jeden Testfall
neu initialisiert
• In der mit @Before annotierten Methode werden
Exemplarvariablen initialisiert
• In der mit @After annotierten Methode werden wertvolle
Testressourcen wie zum Beispiel Datenbank- oder
Netzwerkverbindungen wieder freigegeben
Software-Qualität
Stephan Kleuker
52
Tests von hatFähigkeit
public class Mitarbeiter2Test {
Mitarbeiter m1;
@Before
public void setUp()
setUp() throws Exception {
m1 = new Mitarbeiter("Uwe","Mey
Mitarbeiter("Uwe","Mey");
Uwe","Mey");
m1.addFachgebiet(Fachgebiet.ANALYSE
m1.addFachgebiet(Fachgebiet.ANALYSE);
Fachgebiet.ANALYSE);
m1.addFachgebiet(Fachgebiet.C
m1.addFachgebiet(Fachgebiet.C);
Fachgebiet.C);
m1.addFachgebiet(Fachgebiet.JAVA);
}
@Test
public void testHatFaehigkeit1(){
Assert.assertTrue("vorhandene
Assert.assertTrue("vorhandene Faehigkeit"
Faehigkeit"
,m1.hatFachgebiet(Fachgebiet.C
,m1.hatFachgebiet(Fachgebiet.C));
Fachgebiet.C));
}
@Test
public void testHatFaehigkeit2(){
Assert.assertTrue("nicht
Assert.assertTrue("nicht vorhandene Faehigkeit"
Faehigkeit"
,!m1.hatFachgebiet(Fachgebiet.TEST
,!m1.hatFachgebiet(Fachgebiet.TEST));
Fachgebiet.TEST));
} Software-Qualität
Stephan Kleuker
53
Testablaufsteuerung (1/3)
public class AblaufAnalyse {
@BeforeClass
public static void setUpBeforeClass()
setUpBeforeClass() throws Exception {
System.out.println("
System.out.println("setUpBeforeClass
("setUpBeforeClass");
setUpBeforeClass");
}
@AfterClass
public static void tearDownAfterClass()
tearDownAfterClass() throws Exception {
System.out.println("
System.out.println("tearDownAfterClass
("tearDownAfterClass");
tearDownAfterClass");
}
@Before
public void setUp()
setUp() throws Exception {
System.out.println("
System.out.println("setUp
("setUp");
setUp");
}
Software-Qualität
Stephan Kleuker
54
Testablaufsteuerung (2/3)
@After
public void tearDown()
tearDown() throws Exception {
System.out.println("
System.out.println("tearDown
("tearDown");
tearDown");
}
@Test
public void test1(){
System.out.println("test1");
System.out.println("test1");
}
@Test
public void test2(){
System.out.println("test2");
System.out.println("test2");
}
}
Software-Qualität
Stephan Kleuker
55
Testablaufsteuerung (3/3)
setUpBeforeClass
setUp
test1
tearDown
setUp
test2
tearDown
tearDownAfterClass
Software-Qualität
Stephan Kleuker
56
Testen von Exceptions (1/3)
• Erinnerung: Exception bei vierter Fähigkeit
• Variante 1: Exception in @Test-Annotation festhalten
@Test(expected
@Test(expected=
expected=IllegalArgumentException.class)
IllegalArgumentException.class)
public void testAddFaehigkeit1(){
m1.addFachgebiet(Fachgebiet.TEST
m1.addFachgebiet(Fachgebiet.TEST);
Fachgebiet.TEST);
}
• Falls Exception nicht geworfen wird:
• Vorteil: sehr kompakte Beschreibung
• Nachteil: keine detaillierte Analyse der Exception möglich
Software-Qualität
Stephan Kleuker
57
Testen von Exceptions (2/3)
• Variante 2: „klassisch“ man markiert Stellen, von denen man
erwartet, dass sie nicht ausgeführt werden
@Test
public void testAddFaehigkeit3(){
try{
try{
m1.addFachgebiet(Fachgebiet.TEST
m1.addFachgebiet(Fachgebiet.TEST);
Fachgebiet.TEST);
Assert.fail("fehlende
Assert.fail("fehlende Exception");
Exception");
}catch(IllegalArgumentException
}catch(IllegalArgumentException e){
Assert.assertNotNull(
Assert.assertNotNull(e.getMessage());
e.getMessage());
}catch(Exception
}catch(Exception e){
Assert.fail("unerwartet
Assert.fail("unerwartet "+e);
}
}
Software-Qualität
Stephan Kleuker
58
Testen von Exceptions (3/3)
• wenn keine Exception auftreten soll
@Test
public void testAddFaehigkeit1(){
m1.addFachgebiet(Fachgebiet.C
m1.addFachgebiet(Fachgebiet.C);
Fachgebiet.C);
}
@Test
public void testAddFaehigkeit4(){
try{
try{
m1.addFachgebiet(Fachgebiet.C
m1.addFachgebiet(Fachgebiet.C);
Fachgebiet.C);
}catch(Exception
}catch(Exception e){
Assert.fail("unerwartet
Assert.fail("unerwartet "+e);
}
}
Software-Qualität
Stephan Kleuker
59
Ausblick: langfristige Testnutzung
• Bisher geschriebene Tests werden typischerweise von
Entwicklern geschrieben
• Tests müssen archiviert und bei jedem Release neu
ausführbar sein
• Beispiel: unerfahrener Neuling ersetzt
private List<Fachgebiet> fachgebiete
= new ArrayList<Fachgebiet>();
Software-Qualität
Stephan Kleuker
60
Test weiterer Anforderung (1/2)
• Anforderung „einen änderbaren Nachnamen mit
mindestens zwei Zeichen hat“
@Test
public void testAddKonstruktor2(){
try{
try{
new Mitarbeiter(null,null
Mitarbeiter(null,null);
null,null);
Assert.fail("fehlt
Assert.fail("fehlt Exception ");
}catch(IllegalArgumentException
}catch(IllegalArgumentException e){
}
}
@Test
public void testAddKonstruktor3(){
try{
try{
new Mitarbeiter(null,"X
Mitarbeiter(null,"X");
null,"X");
Assert.fail("fehlt
Assert.fail("fehlt Exception ");
}catch(IllegalArgumentException
}catch(IllegalArgumentException e){
}
Stephan Kleuker
} Software-Qualität
61
Test weiterer Anforderung (2/2)
• fehlt noch: Nachnamenänderung prüfen
@Test
public void testSetNachname1(){
m1.setNachname("Mai");
Assert.assertEquals(m1.getNachname(),
Assert.assertEquals(m1.getNachname(), "Mai");
}
@Test
public void testSetNachname2(){
try{
try{
m1.setNachname("X");
Assert.fail("fehlt
Assert.fail("fehlt Exception ");
}catch(IllegalArgumentException
}catch(IllegalArgumentException e){
}
}
Software-Qualität
Stephan Kleuker
62
Test von equals
@Test
public void testEquals1(){
Assert.assertTrue(m1.toString(),m1.equals(m1));
}
@Test
public void testEquals2(){
Assert.assertFalse(m1
.equals(new Mitarbeiter("Ute","Mey")));
}
@Test
public void testEquals3(){
Mitarbeiter m2 = new Mitarbeiter("Ufo","Hai");
m2.setId(m1.getId());
Assert.assertTrue(m1.equals(m2));
}
Software-Qualität
Stephan Kleuker
63
Was wann testen?
• Beispiel zeigt bereits, dass man sehr viele sinnvolle Tests
schreiben kann
• Frage: Wieviele Tests sollen geschrieben werden?
– jede Methode testen
– doppelte Tests vermeiden
– je kritischer eine SW, desto mehr Tests
– Suche nach Kompromissen: Testkosten vs Kosten von
Folgefehlern
– ein Kompromiss: kein Test generierter Methoden
(Konstruktoren, get, set, equals, hashCode)
• (nächste Veranstaltungen, sinnvolle Testerstellung)
Software-Qualität
Stephan Kleuker
64
Tests ein/und ausschalten
• verschiedene Ansätze, Stellen zu markieren, die noch
entwickelt werden (//TODO)
• häufiger kann man Tests schreiben, bevor Implementierung
vorliegt (-> Design by Concept durch Interfaces)
• Tests können auch sonst so inaktiv geschaltet werden
@Ignore("im
Ignore("im nächsten Release lauffähig")
@Test
public void testChefIstNummer1(){
Mitarbeiter chef = new Mitarbeiter("Ego","Ich
Mitarbeiter("Ego","Ich");
Ego","Ich");
Assert.assertEquals("Nr.1",
Assert.assertEquals("Nr.1", chef.getId(),1);
chef.getId(),1);
}
Software-Qualität
Stephan Kleuker
65
Gefahr von Endlostests
• Tests laufen nacheinander, endet einer nicht, werden andere
nicht ausgeführt
@Test(timeout
@Test(timeout=2000)
timeout=2000)
public void testGodot(){
testGodot(){
while (!m1.getFachgebiete().isEmpty
(!m1.getFachgebiete().isEmpty())
isEmpty())
Assert.assertFalse(m1.hatFachgebiet(
Assert.assertFalse(m1.hatFachgebiet(Fachgebiet.TEST
(m1.hatFachgebiet(Fachgebiet.TEST));
Fachgebiet.TEST));
}
Software-Qualität
Stephan Kleuker
66
Testorganisation
Für große Projekte sind folgende Wünsche bzgl. der Tests
typisch:
a) mehrere Testklassen sollen zusammen laufen können
b) man möchte Tests flexibel kombinieren können;
Testwiederholung soll davon abhängen, welche Klassen
betroffen sein können [schwierige Weissagung]
c) man möchte Tests automatisiert ablaufen lassen können
möglich z. B.:
– JUnit hat Klassen zum einfachen Start von der Konsole
aus
– Nutzung eines cron-Jobs
zu a) und b) folgende Folien: Tests zusammenfassen zu
TestSuites
Software-Qualität
Stephan Kleuker
67
Tests zusammenfassen (1/3) - weitere Testklasse
package verwaltung.mitarbeiter;
import org.junit.Assert;
import org.junit.Test;
public class Mitarbeiter2Test {
@Test
public void testHinzuUndWeg(){
Mitarbeiter m = new Mitarbeiter("Hu","Go");
m.addFachgebiet(Fachgebiet.C);
m.addFachgebiet(Fachgebiet.C);
m.removeFachgebiet(Fachgebiet.C);
Assert.assertFalse(m.hatFachgebiet(Fachgebiet.C));
}
}
Software-Qualität
Stephan Kleuker
68
Tests zusammenfassen (2/3) - einzelne TestSuite
• Anmerkung: Aufbau nicht ganz intuitiv
package verwaltung.mitarbeiter;
verwaltung.mitarbeiter;
import org.junit.runner.RunWith
org.junit.runner.RunWith;
;
import org.junit.runners.Suite;
org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
org.junit.runners.Suite.SuiteClasses;
@RunWith(
RunWith(Suite.class)
Suite.class)
@SuiteClasses({Mitarbeiter2Test.class,
SuiteClasses({Mitarbeiter2Test.class,
MitarbeiterTest.class})
MitarbeiterTest.class})
public class MitarbeiterAllTest {
// hier stehen keine Tests !
}
Software-Qualität
Stephan Kleuker
69
Tests zusammenfassen (3/3) - Suite in Suite
package verwaltung;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import verwaltung.mitarbeiter.MitarbeiterAllTest;
@RunWith(Suite.class)
@SuiteClasses({MitarbeiterAllTest.class})
public class VerwaltungAllTest {}
Software-Qualität
Stephan Kleuker
70
Parametrisierte Tests
• bereits gesehen: häufig wird eine Methode mit
verschiedenen Parametern getestet
• das Schreiben gleichartiger Tests mit ähnlichen Parametern
ist langweilig und zeitaufwändig
• Ansatz: Testdaten irgendwo kompakt speichern und für
Testfälle einlesen
• Lösung in JUnit über mit @Parameter annotierte Methode,
die eine Sammlung von Daten liefert
Software-Qualität
Stephan Kleuker
71
Beispiel: Parametrisierte Tests (1/2)
package verwaltung.mitarbeiter;
verwaltung.mitarbeiter;
import java.util.Arrays;
java.util.Arrays;
import java.util.Collection;
java.util.Collection;
import org.junit.Assert;
org.junit.Assert;
import org.junit.Test;
org.junit.Test;
import org.junit.runner.RunWith;
org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
org.junit.runners.Parameterized.Parameters;
RunWith(
Parameterized.class)
@RunWith
(value = Parameterized.class
)
public class Mitarbeiter3Test {
@Parameters
public static Collection<
Collection<Object[]>
Object[]> daten()
daten() {
Object[][]
Object[][] testdaten = {
{Fachgebiet.ANALYSE,
Fachgebiet.ANALYSE, Fachgebiet.C,
Fachgebiet.C, Fachgebiet.C}
Fachgebiet.C}
,{Fachgebiet.ANALYSE
,{Fachgebiet.ANALYSE,
Fachgebiet.ANALYSE, Fachgebiet.C,
Fachgebiet.C, Fachgebiet.ANALYSE}
Fachgebiet.ANALYSE}
,{Fachgebiet.C
,{Fachgebiet.C,
Fachgebiet.C, Fachgebiet.C,
Fachgebiet.C, Fachgebiet.C}
Fachgebiet.C} };
return Arrays.asList(
Arrays.asList(testdaten);
testdaten);
}
Software-Qualität
Stephan Kleuker
72
Beispiel: Parametrisierte Tests (2/2)
private Mitarbeiter m1;
private Fachgebiet hat;
public Mitarbeiter3Test(Fachgebiet f1, Fachgebiet f2,
Fachgebiet f3) {
m1 = new Mitarbeiter("Oh", "Ha");
m1.addFachgebiet(f1);
m1.addFachgebiet(f2);
hat = f3;
}
@Test
public void testHat()
testHat() {
Assert.assertTrue(m1.hatFachgebiet(hat));
Assert.assertTrue(m1.hatFachgebiet(hat));
}
}
Software-Qualität
Stephan Kleuker
73
Einschränkungen bei Parametrisierung
• Parameter-Methode muss Collection<
Collection<Object[]>
Object[]> liefern;
Methodenname egal
@Parameters
public static Collection<
Collection<Object[]>
Object[]> data()
data() {...
• enthaltene Object[]
Object[] müssen gleich groß sein
• Typen der Array-Elemente müssen zum Konstruktor des
Tests passen
• Man kann in data() auf Dateien zugreifen
• Es gibt kreative Tricks, z. B. dynamische Arraygrößen mit
null-Werten zu ermöglichen
Software-Qualität
Stephan Kleuker
74
Parameter aus Datei testen (1/4) - Erinnerung
• Einfaches Speichern in XML über Serializable
• ergänzen in Mitarbeiter:
import java.io.Serializable;
public class Mitarbeiter implements Serializable{
private static final long serialVersionUID =
458076069326042941L;
public Mitarbeiter(){ // nur für Serialisierung
fachgebiete = new HashSet<Fachgebiet>();
// man bedenke Nachnamenproblem
}
• Anmerkung: Java kann auch mit anderen Dateien (z. B. .csv)
arbeiten
Software-Qualität
Stephan Kleuker
75
Parameter aus Datei testen (2/4) – Daten erzeugen
public class Datenerzeugung {
private final String DATEI="daten.xml";
public Datenerzeugung() throws FileNotFoundException{
XMLEncoder out = new XMLEncoder(new BufferedOutputStream(
new FileOutputStream(DATEI)));
out.writeObject(new Mitarbeiter("Hai","Wo"));
out.writeObject(Fachgebiet.TEST);
out.writeObject(true);
out.writeObject(Fachgebiet.TEST);
out.writeObject(new Mitarbeiter("Su","Se"));
out.writeObject(Fachgebiet.TEST);
out.writeObject(false);
out.writeObject(Fachgebiet.C);
out.close();
}
public static void main(String[] args) throws
FileNotFoundException {
new Datenerzeugung();
}
}
Software-Qualität
Stephan Kleuker
76
Parameter aus Datei testen (3/4) – Daten lesen
@Parameters public static Collection<Object[]> daten()
throws FileNotFoundException {
List<Object[]> ergebnis = new ArrayList<Object[]>();
XMLDecoder in = new XMLDecoder(new BufferedInputStream(
new FileInputStream(DATEI)));
boolean neuerWert = true;
while (neuerWert) {
Object[] tmp = new Object[3];
try {
Mitarbeiter m = (Mitarbeiter) in.readObject();
m.addFachgebiet((Fachgebiet) in.readObject());
tmp[0] = m;
tmp[1] = (Boolean) in.readObject();
tmp[2] = (Fachgebiet) in.readObject();
ergebnis.add(tmp);
} catch (ArrayIndexOutOfBoundsException e) {
neuerWert = false;
}
}
in.close(); return ergebnis;
Stephan Kleuker
77
} Software-Qualität
Parameter aus Datei testen (4/4) – Testen
public class Mitarbeiter4Test {
static private final String DATEI = "daten.xml";
@Parameters ... // letzte Folie
private Mitarbeiter m;
private boolean erwartet;
private Fachgebiet pruef;
public Mitarbeiter4Test(Mitarbeiter m, Boolean b,
Fachgebiet f) {
System.out.println(m + " : " + b + " : " + f);
this.m = m;
this.erwartet = b;
Hai Wo (100)[ TEST ] : true : TEST
this.pruef = f;
Su Se (101)[ TEST ] : false : C
}
@Test
public void testHat() {
Assert.assertTrue(m.hatFachgebiet(pruef)==erwartet);
}
}
Software-Qualität
Stephan Kleuker
78
JUnit - Erweiterungen
• Beispiel: Klasse Runner zur Teststeuerung
• Aus: http://junit.sourceforge.net/javadoc/org/junit/runner/Runner.html
„A Runner runs tests and notifies a RunNotifier of significant events as it
does so. You will need to subclass Runner when using RunWith to
invoke a custom runner. When creating a custom runner, in addition to
implementing the abstract methods here you must also provide a
constructor that takes as an argument the Class containing the tests.
The default runner implementation guarantees that the instances of the
test case class will be constructed immediately before running the test
and that the runner will retain no reference to the test case instances,
generally making them available for garbage collection.“
• Fehlt noch: Möglichkeit, Tests nur durchzuführen, wenn
andere Tests vorher erfolgreich waren (erst Login testen,
dann Funktionalität)
Variante TestNG
Software-Qualität
Stephan Kleuker
79
Herunterladen