Folien ab 7.3.16 - 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 85 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, ab Mi-Abend mit Aufgaben im Netz,
Aufgabenzettel liegen in der Übung vor (Ihre Aufgabe)
http://www.edvsz.hs-osnabrueck.de/kleuker/index.html
• Probleme sofort melden
• Wer aussteigt teilt mit warum
Software-Qualität
Stephan Kleuker
4
Grundvoraussetzungen
Ordentliche Programmierkenntnisse in Java
• Klasse
• Methode
• Klassenvariable und Klassenmethode
• Sichtbarkeit
• Vererbung
• abstrakte Klassen
• Collections (z. B. Liste, Menge)
• Polymorphie
• schön: weitere Sprachen
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
Software-Qualität
Stephan Kleuker
6
Themengebiete (Planung)
1 Fehlerquellen von Software
2 Unit - Tests
3 Äquivalenzklassentests
4 Überdeckungstests
5 Vorgehensmodelle und Testen
6 Mocking
7 Test von Software mit Nutzungsoberflächen
8 Metriken
9 Konstruktive Qualitätssicherung
10 Performance und Speicherauslastung
11 Testautomatisierung
12 Organisation des QS-Prozesses in IT-Projekten
13 Ausblick: Test von Web-Projekten
Software-Qualität
Stephan Kleuker
7
Literatur
• Stephan Kleuker, Qualitätssicherung
durch Softwaretests, Springer Vieweg,
Wiesbaden, 2013
• 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,
Springer Vieweg, 3. Auflage, 2013
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/3)
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 vergesse
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/3)
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
Beispiele markanter Software-Fehler (3/3)
2011
2011
2011
2011
2012
2012
2013
2013
2013
2014
2014
Intel den 8MByte-Bug bei SSDs der Serie 320 führt zu
plötzlichem Kapazitätsverlust, auch nach ersten Firmware-Update
Ausfall von 5.600 Geldautomaten für 24 Stunden in Japan
Störung in der DB-SW, Geldautomaten in Stand-by-Modus, Geräte
erkannten weder Tageslimits noch Kontodeckung (Australien)
Defekte und Übertragungsprobleme von neuer SW führten dazu, dass
in New 22 unschuldige Personen festgenommen wurden (Australien)
Schaltsekunde zur Synchronisation der Uhren mit Erdrotation bereitet
Servern Probleme, legt Webseiten und Datenbanken lahm
Android 4.2: Massive Bugs auf allen Nexus-Geräten
neue Software eines Börsenhandelsunternehmens verursacht einen
Schaden von 440 Millionen US-Dollar, innerhalb von 45 Min. große
Menge verschiedener Aktiensorten an- und wieder verkauft
acht Zeichen - schon stürzen einige Anwendungen unter Mac OS X
10.8 ab (File:///), Schuld wohl systemweite Rechtschreibkontrolle
Computerfehler im Buchungssystem von American Airlines hat
tausende Passagiere stranden lassen, über Stunden keine Abfertigung
Fehler der neuen Playstation 4, löscht Spielstände, zerstört Spiele
Durch doppeltes „goto fail“ gravierende Sicherheitslücke bei Apple
Software-Qualität
Stephan Kleuker
13
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
14
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
15
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)
16
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
17
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
18
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
19
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
20
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
21
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
22
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
23
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
24
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
• generelle Verbesserung nur durch Verbesserung der
Rahmenbedingungen (z.B. der Prozesse)
Software-Qualität
Stephan Kleuker
25
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
26
Aufwand für analytische Qualitätssicherung
C. Jones, Applied Software Measurement, 1991
Software-Qualität
Stephan Kleuker
27
Wann werden Fehler gefunden?
K.-H. Möller, Ausgangsdaten für Qualitätsmetriken, 1996
Software-Qualität
Stephan Kleuker
28
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
29
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
30
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
31
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
32
Einschub: Reguläre Ausdrücke
• Reguläre Ausdrücke beschreiben eine Menge von Worten,
auch Strings genannt
• Typische Fragestellung: Hat ein String den gewünschten
Aufbau? Der Aufbau wird mit regulären Ausdrücken
beschrieben.
• genauer: Theoretische Informatik, Aufbau regulärer Ausdruck
• benötigt: erlaubte Zeichen, Oder-Verknüpfung, Sequenz von
regulären Ausdrücken, beliebige Wiederholung eines
regulären Ausdrucks, leere Menge
• jede Programmiersprache bietet Bibliotheken für reguläre
Ausdrücke zur Analyse und Aufteilung von Strings
• https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html
Software-Qualität
Stephan Kleuker
33
reguläre Ausdrücke in Java (1/5)
public class Main {
public static void pruefe(String regulaererAusdruck, String s){
System.out.println(Pattern.matches(regulaererAusdruck, s));
}
public static void main(String[]
pruefe("q","q");
//
pruefe("qq","q");
//
pruefe("q*","q");
//
pruefe("q*","");
//
pruefe("q+","");
//
pruefe("q+","q");
//
pruefe("q|r","q");
//
pruefe("q|r","r");
//
pruefe("q|r","s");
//
pruefe("(q|r)*","qqrrqq"); //
Software-Qualität
arg){
true
false
true // beliebig oft
true
false // mindestens einmal
true
true // Alternative (oder)
true
false
true
Stephan Kleuker
34
reguläre Ausdrücke in Java (2/5)
pruefe("..","qr");
pruefe("..","qrs");
pruefe(".*","blubb");
pruefe("q?","");
pruefe("q?","q");
pruefe("q?","qq");
pruefe("q{3}","qq");
pruefe("q{3}","qqq");
pruefe("q{3,}","qq");
pruefe("q{3,}","qqq");
pruefe("q{3,5}","qq");
pruefe("q{3,5}","qqqqqq");
pruefe("q\\*","qq");
pruefe("q\\*","q*");
pruefe("q(\\*)","q*");
pruefe("q\\\\","q\\");
Software-Qualität
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
true
false
true
true
true
false
false
true
false
true
false
false
false
true
true
true
Stephan Kleuker
// ein beliebiges Zeichen
// einmal oder keinmal
// genau 3-mal
// mindestens 3-mal
// zwischen 3 und 5-mal
// maskieren, Fluchtsymbol
// Klammern immer erlaubt
// \ in Strings immer \\
35
reguläre Ausdrücke in Java (3/5)
pruefe("[qwe]","w");
// true Alternative
pruefe("[^qwe]","w");
// false //nicht eines der Zeichen
pruefe("[0-9][^a-f]","1A"); // true // von - bis
pruefe("[0-9][^a-f]","1a"); // false
pruefe("\\d+","12345");
// true // \d Ziffer
pruefe("\\D+","12345");
// false // \D keine Ziffer
pruefe("\\s*"," \n\t\f\r "); // true // \s Weißraum
pruefe("\\S*","hall\noo");
// false // \S kein Weißraum
pruefe("\\w*","i_a");
// true // \w = [a-zA-Z_0-9]
pruefe("\\W*"," \n ");
// true // nicht \w
pruefe("\\p{Lower}\\p{Upper}","aA"); // true // klein groß
pruefe("\\p{Lower}\\p{Upper}","Aa"); //false // gibt mehr
// dieser Zeichenklassen
pruefe("(?i)aAa(?-i)Aa","aaaAa"); // true // (?i) Flag Case
// insensitive
pruefe("(?i)aAa(?-i)Aa","aaaaa"); // false // (?-i) Flag
// ausschalten
Software-Qualität
Stephan Kleuker
36
reguläre Ausdrücke in Java (4/5)
pruefe(".*","bl\nub\nb");
// false // . kein Zeilenumbruch
pruefe("(?s).*","bl\nub\nb");// true // . auch für
// Steuerzeichen
pruefe("^a.*","aaa");
// true // ^ markiert Zeilenanfang
pruefe("^a.*"," aaa");
// false
pruefe(".*a$","aaa");
// true // $ markiert Zeilenende
pruefe(".*a$","aaa ");
// false
Pattern pat = Pattern.compile("\\d+");
Matcher mat = pat.matcher("1. Die Antwort ist 42");
while(mat.find()){
System.out.println(mat.group() + " : "
1 : 0-1
+ mat.start() + "-" + mat.end());
42 : 19-21
}
Software-Qualität
Stephan Kleuker
37
reguläre Ausdrücke in Java (5/5)
Pattern pat2 = Pattern.compile("a+");
Matcher mat2 = pat2.matcher("aaaa");
while(mat2.find()) { // greedy: Suche nach maximaler Wortlänge
System.out.println(mat2.group() + " : "
aaaa : 0-4
+ mat2.start() + "-" + mat2.end());
}
Pattern pat3 = Pattern.compile("b+?");
Matcher mat3 = pat3.matcher("bbbb");
while(mat3.find()){ // mit ? nicht greedy
System.out.println(mat3.group() + " : "
+ mat3.start() + "-" + mat3.end());
}
b
b
b
b
:
:
:
:
0-1
1-2
2-3
3-4
H
Pattern pat4 = Pattern.compile("a|o"); //[ao]
ll
String[] splits = pat4.split("Hallo Costa!"); C
for(String s:splits){
st
System.out.println(s);
!
}
}
}
Software-Qualität
Stephan Kleuker
38
2. Unit - Tests
•
•
•
•
•
Annotationen
Varianten von JUnit
Testfälle mit JUnit
Testsuite mit JUnit
Parametrisierte Tests
• Hinweis: Um im Praktikum experimentieren zu können, erst
„wie schreibe ich Tests“ und danach „welche Tests sind
sinnvoll“
• 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
39
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
40
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
41
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
JUnit 5 im Alpha-Stadium (Feb. 16)
Software-Qualität
Stephan Kleuker
42
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
43
Syntax von Annotationen
• Annotationen können Parameter haben
• ohne Parameter: @EinfacheAnnotation
• mit einem Parameter @EinAnno(par="Hallo") oder
@EinAnno("Hallo") (bei nur einem Parameter kann der
Parametername weggelassen werden)
• mit mehreren Parametern werden Wertepaare
(Parametername, Wert) angegeben
@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
44
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\Annotationen\src\Unten.java:2: method does not
override a method from its superclass
@Override public void superTolleSpezialmethode(){
1 error
Software-Qualität
Stephan Kleuker
45
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 als Library in NetBeans integriert
• JUnit ist in Eclipse integriert
• sonst muss das Paket junit.jar zu CLASSPATH hinzugefügt
werden
• seit JUnit 4.11 wird neben JUnit auch Hamcrest-MatcherBibliothek benötigt (vorher fest integriert)
Software-Qualität
Stephan Kleuker
46
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
47
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<>();
} Software-Qualität
Stephan Kleuker
48
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
49
Klasse Mitarbeiter (3/4)
public void addFachgebiet(Fachgebiet f){
this.fachgebiete.add(f);
if(this.fachgebiete.size() > 3){
this.fachgebiete.remove(f);
throw new IllegalArgumentException(
"Maximal 3 Fachgebiete");
}
}
public void removeFachgebiet(Fachgebiet f){
this.fachgebiete.remove(f);
}
public boolean hatFachgebiet(Fachgebiet f){
return this.fachgebiete.contains(f);
}
Software-Qualität
Stephan Kleuker
50
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(){
StringBuilder erg = new StringBuilder(this.vorname +
" " + this.nachname + " (" + this.id +")[ ");
for(Fachgebiet f: this.fachgebiete)
erg.append(f + " ");
erg.append("]");
return erg.toString();
Stephan Kleuker
} Software-Qualität
51
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
52
Anlegen einer Testklasse (1/2)
Software-Qualität
Stephan Kleuker
53
Anlegen einer Testklasse (2/2)
entweder gleiches Paket
wie zu testende Klasse
oder „test.“ davor
erzeugt Beispiel-Code;
auch weglassbar
Software-Qualität
Stephan Kleuker
54
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("erwarteter Vorname Ute"
, m.getVorname().equals("Ute"));
• auch generell nutzbar: Assert.assertEquals(erwartet, gefunden),
Fehlermeldung optional, guter Fehlerausgabe
• JUnit steuert Testausführung, Verstöße bei Prüfungen werden
protokolliert
Software-Qualität
Stephan Kleuker
55
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 waere Ute"
,m.getVorname().equals("Ute"));
Assert.assertTrue("korrekter Nachname waere Mai"
,m.getNachname().equals("Mai"));
}
@Test
public void testEindeutigeId(){
Assert.assertTrue("unterschiedliche ID nicht eingehalten"
, new Mitarbeiter("Ute","Mai").getId()
!= new Mitarbeiter("Ute","Mai").getId());
}
Software-Qualität
Stephan Kleuker
56
Anmerkungen
• keine gute Idee: mehrere Asserts hintereinander (scheitert
das Erste, wird zweites 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() aus, gibt viele weitere
Methoden (auch eigene Bibliotheken)
• Um nicht immer die Klasse Assert angeben zu müssen, kann
man auch (persönlich unschön) folgendes nutzen:
import static org.junit.Assert.*;
Software-Qualität
Stephan Kleuker
57
Ausschnitt: Klassenmethoden von Assert
assertArrayEquals(java.lang.Object[] expecteds,
java.lang.Object[] actuals)
Asserts that two object arrays are equal.
assertEquals(double expected, double actual, double delta)
Asserts that two doubles or floats are equal to within
a positive delta.
assertFalse(boolean condition)
assertNotNull(java.lang.Object object)
assertNull(java.lang.Object object)
assertSame(java.lang.Object expected,
java.lang.Object actual)
Asserts that two objects refer to the same object.
assertThat(T actual, org.hamcrest.Matcher<T> matcher)
Asserts that actual satisfies the condition specified
by matcher.
assertTrue(boolean condition)
fail()
Fails a test with no message.
Software-Qualität
Stephan Kleuker
58
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
59
Tests von hatFähigkeit
public class MitarbeiterTest {
private Mitarbeiter m1;
@Before
public void setUp() throws Exception {
this.m1 = new Mitarbeiter("Uwe","Mey");
this.m1.addFachgebiet(Fachgebiet.ANALYSE);
this.m1.addFachgebiet(Fachgebiet.C);
this.m1.addFachgebiet(Fachgebiet.JAVA);
}
@Test
public void testHatFaehigkeit1(){
Assert.assertTrue("vorhandene Faehigkeit C fehlt"
, this.m1.hatFachgebiet(Fachgebiet.C));
}
@Test
public void testHatFaehigkeit2(){
Assert.assertTrue("nicht vorhandene Faehigkeit TEST gefunden"
, ! this.m1.hatFachgebiet(Fachgebiet.TEST));
} Software-Qualität
Stephan Kleuker
60
Testablaufsteuerung (1/4)
wird einmal für alle Tests vor
public class Ablaufanalyse {
allen Tests ausgeführt (static !)
@BeforeClass
public static void setUpBeforeClass() throws Exception {
System.out.println("setUpBeforeClass");
}
wird einmal für alle Tests vor
nach Tests ausgeführt (static !)
@AfterClass
public static void tearDownAfterClass() throws Exception {
System.out.println("tearDownAfterClass");
}
@Before
public void setUp() throws Exception {
System.out.println("setUp");
}
Software-Qualität
Stephan Kleuker
61
Testablaufsteuerung (2/4)
@After
public void tearDown() throws Exception {
System.out.println("tearDown");
}
@Test
public void test1(){
System.out.println("test1");
}
@Test
public void test2(){
System.out.println("test2");
}
}
Software-Qualität
Stephan Kleuker
62
Testablaufsteuerung (3/4)
bei erster JUnit-Nutzung
hinzugefügte Bibliotheken
Software-Qualität
Stephan Kleuker
63
Testablaufsteuerung (4/4)
Software-Qualität
Stephan Kleuker
64
Testen von Exceptions (1/3)
• Erinnerung: Exception bei vierter Fähigkeit
• Variante 1: Exception in @Test-Annotation festhalten
@Test(expected=IllegalArgumentException.class)
public void testAddFaehigkeit1(){
this.m1.addFachgebiet(Fachgebiet.TEST);
}
• Falls Exception nicht geworfen wird:
• Vorteil: sehr kompakte Beschreibung
• Nachteil: keine detaillierte Analyse der Exception möglich
Software-Qualität
Stephan Kleuker
65
Testen von Exceptions (2/3)
• Variante 2: „klassisch“ man markiert Stellen, von denen man
erwartet, dass sie nicht ausgeführt werden
@Test
public void testAddFaehigkeit1a(){
try{
this.m1.addFachgebiet(Fachgebiet.TEST);
Assert.fail("fehlende Exception");
}catch(IllegalArgumentException e){
Assert.assertNotNull(e.getMessage()); // oder leer
}catch(Exception e){
Assert.fail("unerwartet " + e);
}
}
Software-Qualität
Stephan Kleuker
66
Testen von Exceptions (3/3)
• wenn keine Exception auftreten soll
@Test
public void testAddFaehigkeit2(){
this.m1.addFachgebiet(Fachgebiet.C);
}
@Test
public void testAddFaehigkeit2a(){
try{
this.m1.addFachgebiet(Fachgebiet.C);
}catch(Exception e){
Assert.fail("unerwartet " + e);
}
}
Software-Qualität
Stephan Kleuker
67
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<>();
Software-Qualität
Stephan Kleuker
68
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
69
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
70
Tests zusammenfassen (2/3) - einzelne TestSuite
• Anmerkung: Aufbau nicht ganz intuitiv
package verwaltung.mitarbeiter;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({ Mitarbeiter2Test.class
, MitarbeiterTest.class})
public class MitarbeiterAllTest {
// hier stehen keine Tests !
}
Software-Qualität
Stephan Kleuker
71
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
72
Test weiterer Anforderung (1/2)
• Anforderung „einen änderbaren Nachnamen mit
mindestens zwei Zeichen hat“
@Test
public void testAddKonstruktor2(){
try{
new Mitarbeiter(null,null);
Assert.fail("fehlt Exception ");
}catch(IllegalArgumentException e){
}
}
@Test
public void testAddKonstruktor3(){
try{
new Mitarbeiter(null,"X");
Assert.fail("fehlt Exception ");
}catch(IllegalArgumentException e){
}
Stephan Kleuker
} Software-Qualität
73
Test weiterer Anforderung (2/2)
• fehlt noch: Nachnamenänderung prüfen
@Test
public void testSetNachname1(){
this.m1.setNachname("Mai");
Assert.assertEquals(this.m1.getNachname(), "Mai");
}
@Test // hier wird ein Fehler gefunden!
public void testSetNachname2(){
try{
this.m1.setNachname("X");
Assert.fail("fehlt Exception ");
}catch(IllegalArgumentException e){
}
}
Software-Qualität
Stephan Kleuker
74
Test von equals
@Test
public void testEquals1(){
Assert.assertTrue(this.m1.toString(), this.m1.equals(m1));
}
@Test
public void testEquals2(){
Assert.assertFalse(this.m1
.equals(new Mitarbeiter("Ute","Mey")));
}
@Test
public void testEquals3(){
Mitarbeiter m2 = new Mitarbeiter("Ufo","Hai");
m2.setId(this.m1.getId());
Assert.assertTrue(this.m1.equals(m2));
}
Software-Qualität
Stephan Kleuker
75
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ächster Block, sinnvolle Testerstellung)
Software-Qualität
Stephan Kleuker
76
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 Conctract durch Interfaces)
• Tests können auch sonst so inaktiv geschaltet werden
@Ignore("erst im Release 42.0 lauffähig")
@Test
public void testChefIstNummer1(){
Mitarbeiter chef = new Mitarbeiter("Ego","Ich");
Assert.assertEquals("Nr.1", chef.getId(),1);
}
Software-Qualität
Stephan Kleuker
77
Gefahr von Endlostests
• Tests laufen nacheinander, endet einer nicht, werden andere
nicht ausgeführt
@Test(timeout=2000)
public void testGodot(){
while (!m1.getFachgebiete().isEmpty())
Assert.assertFalse(m1.hatFachgebiet(Fachgebiet.TEST));
}
Software-Qualität
Stephan Kleuker
78
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
• Hinweis: gibt flexiblere Erweiterung JUnitParams
https://github.com/Pragmatists/JUnitParams
Software-Qualität
Stephan Kleuker
79
Beispiel: Parametrisierte Tests (1/2)
package verwaltung.mitarbeiter;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(value = Parameterized.class)
public class Mitarbeiter6Test {
@Parameters
public static Collection<Object[]> daten() {
Object[][] testdaten = {
{Fachgebiet.ANALYSE, Fachgebiet.C, Fachgebiet.C}
,{Fachgebiet.ANALYSE, Fachgebiet.C, Fachgebiet.ANALYSE}
,{Fachgebiet.C, Fachgebiet.C, Fachgebiet.C} };
return Arrays.asList(testdaten);
}
Software-Qualität
Stephan Kleuker
80
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() {
Assert.assertTrue(m1.hatFachgebiet(hat));
}
Software-Qualität
Stephan Kleuker
81
Parametrisierung genauer angesehen
public class ParametrisierterTest{
tpa1
Collection<Object[]>
tpb1
tpa2
…
tpan
tpb2
…
tpbn
tpk2
…
tpkn
Object[]
entspricht einer
Parameterliste
...
tpk1
publicpublic
class ParametrisierterTest(par1,
ParametrisierterTest(par1,par2,
par2,...,
...,parn){...
parn){ ...
• Parameter tpa (Zeile) gehören zu einem Test und können im
Test beliebig genutzt werden (Berechnung, Prüfung, …)
Software-Qualität
Stephan Kleuker
82
Einschränkungen bei Parametrisierung
• Parameter-Methode muss Collection<Object[]> liefern
@Parameters
public static Collection<Object[]> data() {...
• enthaltene 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
83
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
84
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
85
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
86
} 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
87
Testauswahl mit Kategorien (1/3)
• Einfache Interfaces werden als Markierung von Kategorien
genutzt (spart weitere Schlüsselworte)
public interface Basic { /* markiert Kategorie */ }
public interface Inkrement2 { /* markiert Kategorie */ }
• man kann Test-Klassen markieren
@Category({Basic.class, Inkrement2.class})
public class BTest {
}
@Test
public void testb() {
System.out.println("b");
}
Software-Qualität
Stephan Kleuker
88
Testauswahl mit Kategorien (2/3)
• man kann einzelne Tests markieren
package test;
import org.junit.Test;
import org.junit.experimental.categories.Category;
public class ATest {
@Test
public void testa1() {
System.out.println("a1");
}
}
@Category(Basic.class)
@Test
public void testa2() {
System.out.println("a2");
}
Software-Qualität
Stephan Kleuker
89
Testauswahl mit Kategorien (3/3)
• man kann Ausführung variieren
@RunWith(Categories.class)
@IncludeCategory(Basic.class)
@SuiteClasses({ ATest.class, BTest.class })
public class BasicTestSuite {
}
@RunWith(Categories.class)
@IncludeCategory(Basic.class)
@ExcludeCategory(Inkrement2.class)
@Suite.SuiteClasses({ ATest.class, BTest.class })
public class OnlyBasicTestSuite {
}
Software-Qualität
Stephan Kleuker
a2
b
a2
90
Rules
• Teststeuerung kann durch Regeln angepasst werden
• Regeln sind Objekte, die bestimmte Funktionalität anbieten, die
durch ihre Nutzung Abläufe vereinfachen
• typisch: Zusammenfassung von Aktionen @Before und @After
mit optional weiterer Funktionalität
• JUnit beinhaltet schon einige Regeln selbst
• Entwickler können eigene Regeln schreiben (Interface beachten)
• Ergänzungsbibliotheken bieten zusätzliche Regeln an
• Annotation @Rule für Exemplarvariablen
• Annotation @ClassRule für Klassen nutzbar (-> static,
@BeforeClass, @AfterClass)
Software-Qualität
Stephan Kleuker
91
Beispiel-Regel: Nutzung temporärer Dateien
@Test // alte Variante
public void mitDatebearbeitungTest() throws IOException {
File verzeichnis = new File("subfolder");
verzeichnis.mkdir();
File datei= new File("subfolder/myfile.txt");
datei.createNewFile();
Assert.assertTrue(datei.exists());
// ... muss alles von Hand aufgeräumt werden
}
@Rule // neue Variante
public TemporaryFolder folder = new TemporaryFolder();
@Test
public void testUsingTempFolder() throws IOException {
File verzeichnis = this.folder.newFolder("subfolder");
File datei = this.folder.newFile("subfolder/myfile.txt");
Assert.assertTrue(datei.exists());
// ...
}
Software-Qualität
Stephan Kleuker
92
Beispiel-Regel: Angabe erwarteter Exception
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void nichtDurchNullTest() {
this.thrown.expect(ArithmeticException.class);
this.thrown.expectMessage("by zero"); // Teiltext
int bumm = 7 / (7-7);
}
@Test
public void dateiErstAnlegenTest() throws Exception{
this.thrown.expect(FileNotFoundException.class);
File datei= new File("hallo.txt");
datei.delete();
FileInputStream in = new FileInputStream(datei);
}
Software-Qualität
Stephan Kleuker
93
Eigene minimale Regel (1/2): Deklaration
public class MeineRegel implements TestRule{
@Override
public Statement apply(Statement base, Description desc) {
System.out.println(desc);
return new Statement(){
@Override
public void evaluate() throws Throwable {
System.out.println("folge meinen Regeln");
base.evaluate(); // eigentlichen Test ausfuehren
System.out.println("folgtet meinen Regeln");
}
};
}
}
Software-Qualität
Stephan Kleuker
94
Eigene minimale Regel (2/2): Beispielnutzung
public class RuleAnalyseTest {
@Rule
public MeineRegel mr = new MeineRegel();
@Test
public void test1(){
System.out.println("in test1");
}
@Test
public void test2(){
System.out.println("in test2");
}
}
Software-Qualität
Stephan Kleuker
test1(test.RuleAnalyseTest)
folge meinen Regeln
in test1
folgtet meinen Regeln
test2(test.RuleAnalyseTest)
folge meinen Regeln
in test2
folgtet meinen Regeln
95
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
96
Herunterladen