Software-Engineering II
Objektorientiertes Testen
1
TIT10AIK @ WS 2012
Themenübersicht
»
»
»
»
»
»
»
»
»
Objektorientierung
Aspektorientierung
Vorgehensmodelle
UML
Analyse- & Entwurfsmuster
Objektorientiertes Testen
Versionsverwaltung
Refactoring
Labor (Praktischer Teil)
2
TIT10AIK @ WS 2012
Unit-Testing mit JUnit
Pragmatic Unit Testing
in Java with JUnit
Andrew Hunt,
David Thomas
176 Seiten
ISBN: 0-974-5140-12
(Englisch)
3
TIT10AIK @ WS 2012
Objektorientiertes Testen
» Testen ist ein wichtiger
Bestandteil des SoftwareLifecycles
» Testen objektorienter Software
bringt verglichen mit
funktionaler Programmierung
einige Erschwernisse mit sich
4
TIT10AIK @ WS 2012
Probleme bei der
Objektorientierung I
» Nachdem die objektorientierte SoftwareEntwicklung begann, sich durchzusetzen,
blieb objektorientiertes Testen zunächst
unbeachtet
» Es gab sogar Meinungen, dass
Objektorientierung das Testen von Software
vereinfacht:
„... the use of object-oriented design doesn’t change any
basic testing principles; what does change is the granularity
of the units tested.“ (Grady Booch)
„Both testing and maintenance are simplified by an objectoriented approach...“ (James Rumbaugh)
5
TIT10AIK @ WS 2012
Probleme bei der
Objektorientierung II
» Im Allgemeinen die selben
Anforderungen wie bei
funktionaler Programmierung
» Generierung von authentischen
Testdaten
» Validierung der Testergebnisse
» Das Programm gilt als korrekt,
wenn der Ist-Zustand dem
spezifizierten Soll-Zustand
entspricht
6
TIT10AIK @ WS 2012
Unzählige Zustände
» Methoden können in objektorientierten
Programmen abhängig vom Zustand der Klasse
sein, welcher durch ihre Attribute geprägt
wird
» Ein Aufruf einer Methode kann je nach
Vorgeschichte der Klasse ein beliebig
differenziertes Ergebnis liefern
» Eine Klasse zu 100% zu testen führt zu einer
exponentiellen Steigerung der Testfälle
» Es würde bei den meisten komplexen ProgrammStrukturen den finanziellen Rahmen des Projekts
sprengen
7
TIT10AIK @ WS 2012
Generik und Vererbung
» Klassen sollten generisch und für
eine große Anzahl von
Anwendungsfällen geschrieben sein
» Beim Testen nicht vorhersehbar, wie eine
Klasse benutzt wird
» Prognose der Fälle erforderlich
» Durch Vererbung entstehen neue
Abhängigkeiten die wiederum getestet
werden müssen
» Werden Fehler in Basisklassen nicht
erkennt, erben alle Subklassen die
Fehler von der Basisklasse
8
TIT10AIK @ WS 2012
Automatisierte Tests
» Nach dem Definieren von Testfällen kann
automatisiert die ganze Testsuite getestet
werden
» Vorteile:
» Fehler, die durch Abhängigkeiten unbemerkt
entstanden sind, können einfach gefunden werden
» Schnelle Möglichkeit um ein System komplett auf
Funktionalität zu prüfen
» Verringert die Zeit für das Debuggen
» Gibt Vertrauen in den Quellcode
» Verbessert das Design, da schon zu Beginn
Gedanken über die Verwendung (Testbarkeit) des
Codes gemacht werden müssen
» Voraussetzung:
» Gute Code-Abdeckung der Tests
9
TIT10AIK @ WS 2012
Generelle Grundsätze
» Teste alles, was schief gehen kann
» Teste alles, was schief ging (Bugs)
» Neuer Quellcode ist solange
fehlerhaft bis man das Gegenteil
bewiesen hat
» Schreibe mindestens so viel Testcode
wie Programmcode
» Führe Tests lokal bei jedem
Compilieren aus
» Führe alle Tests vor dem Check-In in
das Repository aus
10
TIT10AIK @ WS 2012
Was soll getestet werden?
» Regel: „Use your Right-Bicep“
»R
»B
»I
»C
»E
»P
ight
oundary
nverse
ross-Check
rror-Conditions
erformance
11
TIT10AIK @ WS 2012
R-BICEP - Right
» Die einfachste Kondition
» Teste, ob das Ergebnis richtig ist
int[] numbers = { 3, 1, 4, 2 };
Assert.assertEquals( 4, MaxValue( numbers ) );
12
TIT10AIK @ WS 2012
R-BICEP - Boundary
» Mit Grenzwerten testen
» Sonderzeichen, Umlaute
» Leere oder fehlende Werte, bspw. null,
Leerstring, 0
» Unerwartete Werte, bspw. 10,000 als
Alter
» Duplikate in Listen, die keine haben
dürften
» Sortierte und unsortierte Werte, bpsw.
für Sortieralgorithmen
» Befehle nicht in erwarteter Reihenfolge
ausführen
13
TIT10AIK @ WS 2012
R-BICEP –
Inverse Relationship
» Einige Methoden können durch
die Invers-Methode verifiziert
werden
» Definitionsbereiche beachten
double x = MyMath.Sqrt( 4.0 );
Assert.assertTrue( Math.abs( 4.0 - x*x ) < 0.0001 );
14
TIT10AIK @ WS 2012
R-BICEP - Cross-Check
» Manche Ergebnisse können mit
alternativen Implementierungen
geprüft werden
double x = MyMath.Sqrt( 100 );
double y = Math.Sqrt( 100 );
Assert.assertTrue( Math.abs( x – y ) < 0.0001);
15
TIT10AIK @ WS 2012
R-BICEP – Error-Conditions
» Mit ungültigen Eingaben testen
» Exceptions provizieren und erwarten
» Umgebungsprobleme testen
»
»
»
»
Speicherüberlauf
Festplatte voll
Systemuhrzeit inkonsistent (manipuliert)
Dauerhafter oder temporärer NetzwerkAbbruch
» Unzureichende Benutzer-Rechte
» Systemauslastung
» Eingeschränkte oder sehr hohe
Bildschirmauflösung
16
TIT10AIK @ WS 2012
R-BICEP - Performance
» Bei manchen Methoden sind
Performance-Analysen möglich
long start = System.currentTimeMillis();
this.sortList();
long end
= System.currentTimeMillis();
Assert.assertTrue( ( end - start ) < 1.0 );
17
TIT10AIK @ WS 2012
Gute Tests
» A utomatic
»T
»R
»I
»P
horough
epeatable
ndependant
rofessional
18
TIT10AIK @ WS 2012
A TRIP - Automatic
» Unit-Tests müssen automatisch
ablaufen können
» Starten der Tests
» Prüfen der Ergebnisse
» Es darf kein manueller Schritt
notwendig sein
» Datenbank-Zeilen einfügen
» Dateien erstellen
»…
19
TIT10AIK @ WS 2012
A TRIP - Thorough
» Teste alles, bei dem es
wahrscheinlich ist, dass es schief
geht
» Teste zumindest die wichtigsten
Eigenschaften
» Grenzwerte
» Fehlende und ungültige Werte
» Die Konsequenz, mit der getestet
wird, muss für jedes Projekt neu
entschieden werden
20
TIT10AIK @ WS 2012
A TRIP - Repeatable
» Tests sollten
» immer wieder ausführbar sein
» in jeder Reihenfolge ausführbar
sein
» immer die gleichen Ergebnisse
liefern
21
TIT10AIK @ WS 2012
A TRIP - Independant
» Tests sollten
» Klein und sauber sein
» Unabhängig von der Umgebung sein
» Unabhängig von einander sein
» Teste immer nur eine Sache zu
einer Zeit
22
TIT10AIK @ WS 2012
A TRIP - Professional
» Tests sind richtiger Quellcode
» Sie müssen deshalb nach den
selben professionellen
Standards wie der Programmcode
» geschrieben sein
» gewartet werden
23
TIT10AIK @ WS 2012
Dependency Injection 1
» Klassen mit direkten Abhängigkeiten
sind schwer testbar
» Sie können nicht einzeln, sondern
nur als System getestet werden
Zu testende Klasse
24
TIT10AIK @ WS 2012
Dependency Injection 2
» Die abhängige Klasse bekommt eine
Referenz auf ihre Delegate-Klasse
gesetzt
» Der Typ der Referenz ist dabei
nicht die Klasse selbst sondern
ein Interface*
Zu testende Klasse
25
TIT10AIK @ WS 2012
Dependency Injection 3
» Im Test-Code kann nun der Klasse ein Delegate
gesetzt werden, welches dasselbe Interface
implementiert, sich jedoch nach von der TestKlasse vorgegebenen Regeln verhält
» Diese Alternativ-Klassen nennt man MockKlassen (Mock = Attrappe)
26
TIT10AIK @ WS 2012
[Frameworks] Mockito
» Mocking-Framework
» Stellt Mocks zur Verfügung
Class2 delegate = Mockito.mock(Class2.class);
Mockito.when(delegate.foo(10)).thenReturn(“String“);
new Class1().setDependancy(delegate);
Mit verify kann später geprüft werden, ob ein Aufruf stattfand:
Mockito.verify(delegate).foo(10);
27
TIT10AIK @ WS 2012
[Frameworks] Spring (I)
» Dependancy Injection Framework
@Resource-Annotation
class Class1{
@Resource
private iClass2 dependancy;
}
» Dependancies sind konfigurierbar
...
<bean id="dependancy" class="Class2“ />
...
28
TIT10AIK @ WS 2012
[Frameworks] Spring (II)
» Komplexe Instanziierungen möglich
...
<bean id="class1" class="Class1">
<property name="dependancy" ref=“iClass2" />
</bean>
<bean id=“iClass2" class="Class2">
<constructor-arg value="Hallo Welt" />
</bean>
...
Entspricht:
iClass2 class2 = new Class2("Hallo Welt");
Class1 class1 = new Class1();
Class1.setDependancy(class2);
Vorteil:
(=austauschbar)
Variable Parameter und Abhängigkeiten sind konfigurierbar!
29
TIT10AIK @ WS 2012
Dependency Injection 4
» OOP Design Pattern
» Einsatzgebiete nicht nur auf
OOP Testing beschränkt
» Immer dann ideal, wenn direkte
Abhängigkeiten vermieden werden
sollen
30
TIT10AIK @ WS 2012
Werkzeug JUnit
» In Eclipse und NetBeans
» Ohne Eclipse:
» http://www.junit.org/
» In Eclipse das JUnit-Library
einbinden
» Projekt-Properties
» Java Build Path
» Libraries
31
TIT10AIK @ WS 2012
Testfall erstellen
» Neue (Test-)Klasse erstellen
» vorzugsweise in einem separaten Package
für unit-tests
» Neue Methode erstellen, die einen
Test durchführt
» Methode mit der Annotation
@org.junit.Test versehen
» Package Explorer:
» Rechtsklick auf Klasse
» Run as
» JUnit test
32
TIT10AIK @ WS 2012
Aufbau eines Tests
package unittest.test;
public class SimpleTest
{
Testklasse
@org.junit.Test public void testcase()
{
// …
}
Test-Methode
Test-Code
}
33
TIT10AIK @ WS 2012
Assertions
» Die Klasse org.junit.Assert bietet statische
Funktionen, um Tests durchzuführen
» Assert.assertTrue( boolean )
» Test bestanden, wenn der übergebene Wert true ist
» Assert.assertFalse( boolean )
» Test bestanden, wenn der übergebene Wert false ist
» Assert.assertEquals( Object, Object )
» Test bestanden, wenn beide übergebene Objekte „gleich“
sind (Bsp.: Strings mit gleichem Inhalt)
» Assert.assertSame( Object, Object )
» Test bestanden, wenn es sich bei den übergebenen
Objekten und die selbe Instanz handelt
» Assert.assertNotNull( Object )
» Test bestanden, wenn das übergebene Objekt nicht null
ist
34
TIT10AIK @ WS 2012
Beispiel-Testfall
package unittest.test;
import org.junit.Assert;
public class SimpleTest {
@org.junit.Test public void testcase()
{
Assert.assertTrue( Math.PI > 3 ); // will succeed
}
@org.junit.Test public void badTestcase()
{
Assert.assertTrue( Math.PI < 3 ); // bound to fail
}
}
35
TIT10AIK @ WS 2012
Ausführen des Tests
Start des
Testvorgangs
36
TIT10AIK @ WS 2012
Test-Ergebnisse
Indiziert,
dass alle
Testfälle
erfolgreich
waren
Ein Testfall
ist
fehlgeschlagen
37
TIT10AIK @ WS 2012
setUp & tearDown
»
Benötigen alle Tests einer Testklasse gemeinsame Ressourcen, können
diese in einer setUp-Methode alloziert werden
»
»
Ressourcen, die in der setUp-Methode alloziert werden, können in der
tearDown-Methode wieder freigegeben werden
»
»
Dazu wird die Methode mit der Annotation @org.junit.Before versehen
Die Methode wird mit der Annotation @org.junit.After versehen
Die beiden Methoden werden vor und nach jedem Test ausgeführt
@org.junit.Before public void setUp(){
this.dbconnection.open();
}
@org.junit.After public void tearDown() {
this.dbconnection.close();
}
@org.junit.Test public void testcase1()
{
this.dbconnection.…;
}
@org.junit.Test public void testcase2()
{
this.dbconnection.…;
}
38
TIT10AIK @ WS 2012
Einfachere Annotations
» Durch den Import von org.junit.*
bzw. den benötigten Elementen kann
man auf die Paketnamen verzichten
import org.junit.*;
class MyTest
{
@Before public void setUp(){
…
}
@Test public void testcase1()
{
…
}
}
39
TIT10AIK @ WS 2012
Exceptions
» Exceptions, die während des Tests
auftreten werden von JUnit abgefangen und
bei der Auswertung als Fehler ausgewiesen
» Möchte man explizit testen, ob eine
spezielle Exception geworfen wird, kann
man das durch die Erweiterung der
Annotation erreichen:
@Test(expected= [Exception-Name].class)
Beispiel:
@Test(expected= IndexOutOfBoundsException.class) public void testException()
{
new ArrayList<Object>().get(0); // wirft Exception
}
40
TIT10AIK @ WS 2012
[Tools] Code-Coverage
» Analysieren, welche CodeStellen durch Unit-Tests
bereits abgedeckt sind
» Einfaches Auffinden von
ungetestetem Code
» „Nur getesteter Code kann als
funktionsfähig angesehen werden!“
» Beispiel: Clover
41
TIT10AIK @ WS 2012

Objektorientiertes Testen