Weitere ähnliche Inhalte
Ähnlich wie Test-Driven-Development mit JUnit 4 (20)
Mehr von Jörn Dinkla (16)
Test-Driven-Development mit JUnit 4
- 2. Vorstellung
• Dipl.-Inform. Jörn Dinkla
• Schwerpunkte
• Java Entwicklung (J2SE, JEE)
• Moderne Programmiersprachen
• Groovy, Ruby, Haskell, Scala
• Modellgetriebene Entwicklung
• Automatisierung
• Eclipse
• Plugin-Entwicklung
• CUDA, OpenCL
• Hobbies
• Musik, Literatur
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 2
- 4. Überblick: JUnit und Testwerkzeuge
• Grundlagen des Testen
• JUnit
• Tests und Design
• Standards
• Nebenläufigkeit
• Erweiterungen von JUnit
• TestNG
• Akzeptanztests mit Fit und FitNesse
• Zwischendurch
• Hands-on
• Gemeinsam entwickeln
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 4
- 6. Software-Qualität wird vernachlässigt
• Aus der PC Welt vom April 2008
• „Software-Hersteller haben häufig nur ein Ziel: Ihre
Anwendungen schnell zu entwickeln und Projekte
abzuschließen.“
• „Das Testen der Software und die damit verbundene
Qualitätssicherung kommen dabei oft zu kurz.“
• „eher geringes Interesse für das Testen von Software
und der Kontrolle der Entwicklungsarbeit“ in
Unternehmen
• Aus http://www.pcwelt.de/start/software_os/systemtools/
news/1860669/software_qualitaet_wird_vernachlaessigt/
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 6
- 7. Klassifikation von Tests
• Klassifikation nach Umfang
• Funktional
• Korrektheit bezüglich der Spezifikation
• Terminierung
• Nebenläufige Eingenschaften
•Thread-Sicherheit
• „Nicht-funktional“
• Performance: Laufzeit und Platz
• Load, Stress
• Sicherheit
• Benutzbarkeit
• Interoperabilität
• Zuverlässigkeit
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 7
- 8. Klassifikation von Tests
• Klassifikation nach Wissen
• Funktion: Black-Box
• Struktur: White-Box
• Klassifikation nach Struktur
• Unit
• Einzelne Teile
• Integration
• Zusammenspiel mehrerer Teile
• System
• Das gesamte System
• User Acceptance Test
• Erwartungen der Benutzer
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 8
- 9. Stetiger Übergang
• Unit-, Integration- und Systemtests
• Ergänzen sich
• Detailierungsgrad und Umfang
• Tiefe und Breite
• Horizontal und vertikal
• Design der Tests
• Top-Down
• Vom System- über Integrations- zu Unit-Tests
• Unit-Tests resultieren als Reproduktionen von Fehlern
• Bottom-Up approach
• Von Unit-Tests über Integrations- zum System-Test
• "a good functional test can be decomposed into a
number of unit tests" [BS08]
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 9
- 10. Korrektheit
• Korrektheit
• Bezüglich einer Spezifikation
• Abgeleitet aus den Anforderungen/Pflichtenheft
• Partiell und total (mit Terminierung)
• Korrektheitsbeweise
• Hoare-Kalkül { P } S { Q }
• Zusicherungen
•Vorbedingung P
•Statements / Anweisungen S
•Nachbedingung Q
• Wenn P gilt und S ausgeführt wird, muss Q gelten
• Invarianten
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 10
- 11. Korrektheit
• Spezifikation ist eine „logische Theorie“ über den Code
• Mehr oder weniger formalisiert
• Zu zeigen ist
• Spezifikation <=> Code
• Äquivalenz, nicht Implikation !
• Der Code soll genau und nur die Spezifikation erfüllen
• Korrektheitsbeweise sind aufwendig durchzuführen
• Wird in Teilbereichen gemacht
• Satelliten, Raumfahrt, Medizin
• Daher Tests
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 11
- 12. Traditionelles Testen
• Tests traditionell am Ende des Projekts
• Analyse, Design, Implementierung, Test
• Oft spezielle Testteam (QS/QA)
• Nachteile
• Späte Rückmeldung
• Entwickler müssen sich erst wieder in den Code
einarbeiten
• Testabdeckung oft nicht ausreichend
• Kollateralschäden
• Zeitaufwendiges, fehleranfälliges manuelles Testen
• Probleme des "ad hoc" Testens
• System.out.println(), Debugger
• Wissen bleibt im Kopf des Entwicklers
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 12
- 13. Agiles Testen
• Agile Methoden
• Agil: flink, beweglich
• Extreme Progamming, Scrum
• Geringer bürokratischer Aufwand
• Wenige Regeln
• Berücksichtigung technischer und sozialer Probleme
• Einteilung des Projekts in kleinere Schritte
• Feature
• Eine Säule ist die ...
• Testgetriebene Entwicklung
• Test driven Development (TDD)
• "test first"
• „test, code, refactor“
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 13
- 14. Testen
• Mischformen zwischen Tradition und TDD möglich
• „write a little, test a litte, ...“
• Pragmatischer Ansatz
• "testing is a choice, not an infectious disease" [BS08]
• "testing is a means to an end, and the end is better
software" [BS08]
• "testing ... is not a golden hammer in a world of
nails" [BS08]
• „test until fear turns to boredom“ [R05]
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 14
- 15. Möglichkeiten des Testens
• Erfüllung der Anforderungen
• Demonstration, das Code funktioniert
• Tests auf verschiedenen Plattformen
• Regressionstests
• Wiedereinführung von bekannten Fehlern
• Verhinderung von Kollateralschäden
• Abhängigkeiten zwischen den Komponenten
• Ermöglicht sicheres Refactoring
• Tests bis zur ausführbaren Spezifikation möglich
• Automatisierung von Tests
• Entwickler haben den Kopf frei für neue Features
• Sicherheitsnetz
• „peace of mind“
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 15
- 16. Automatisierung von Tests
• Welche Aufrufarten?
• Befehlsgesteuert
• Zeitgesteuert
• Ereignisgesteuert
• „Continuous-Integration“
• Wann ?
• Abhängig von der Dauer und den benötigten Ressourcen
• Sollten so oft wie möglich laufen
• Was wird benötigt ?
• Versionsverwaltung
• Automatisierte Tests
• Rückmeldung
• Email, Web-Seiten, RSS-Feeds, Lavalampen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 16
- 17. Beim Testen zu berücksichtigen
• Client
• GUI
• Rich Client
• Web Client
• Rich-Client
• Business-Logik
• Persistenzschicht / Datenanbindung
• Server / Service
• Middleware / Applikationsserver
• Business-Logik
• Persistenzschicht / Datenanbindung
• Datenbanken
• Speicherung und Zugriff
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 17
- 18. Beim Testen zu berücksichtigen
• Programme
• Sequentiell
• Parallel
• Gleiche Aufgaben, mehrere Datenströme
• Z. B. Grafikkarten
• Nebenläufig / Concurrent
• Threads mit unterschiedlichen Aufgaben
• Verteilt
• Threads auf mehreren Rechnern, SOA
• Kommunikation
• Synchron
• Asynchron
• Auf das Ergebnis wird nicht gewartet
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 18
- 20. JUnit
• De facto Standard in der Java Welt
• 2001 von Kent Beck und Erich Gamma
• Adaption von SUnit aus der Smalltalk Welt (1997)
• Versionen 3.8 und 4.5
• 3.8
• Basiert auf Vererbung
• JUnit 3.8.2 vom 03.09.2002
• 4.5
• Basiert auf Annotationen
•Java 5
• Konzepte von TestNG übernommen
• JUnit 4.5 vom 08.08.2008
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 20
- 21. JUnit 4: Ein einfaches Beispiel
• Funktion, die ihr Argument verdoppelt
package example;
public class MyMath {
/**
* Returns i*2.
* @param i
An integer.
* @return
Twice the integer.
*/
public static int mal2(int i) {
return i+i;
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 21
- 22. JUnit 4: Ein einfaches Beispiel
• Annotationen
• Ausführung der mit @Test annotierten Methoden
• Zusicherungen
• Erwartete Ergebnisse mit Zusicherungen („assertions“)
import org.junit.Test;
import static example.MyMath.mal2;
import static org.junit.Assert.*;
public class MyMathTest {
@Test
public void mal2Test() { Annotation
assertEquals(0, mal2(0));
assertEquals(-2, mal2(-1));
assertEquals(4, mal2(2));
} Zusicherunge
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 22
- 23. JUnit 4: IDE-Integration
• NetBeans 6.1
• Shift-F6
• Eclipse 3.4
• Run As
• JUnit-Test
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 23
- 24. JUnit4: Kommandozeile
• Aufruf eines einzelnen Tests auf der Kommandozeile
• java -cp CLASSPATH org.junit.runner.JUnitCore KLASSE
• Wird selten gemacht
• Da JUnit meistens über Ant oder IDE aufgerufen wird
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 24
- 25. JUnit4: Ant-Integration
• Integration in Ant
• <junit> und <junitreport> Tasks
• Später mehr ...
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 25
- 26. Ergebnisse von Tests
• Error
• Während der Ausführung trat ein Fehler auf
• Beispiel: Nicht behandelte Exceptions
• Failure
• Ungültige Zusicherung
• Success
• Sonst
• Warum?
• Integration in Java-Exceptions
• Unchecked Exceptions
• Checked Exceptions
•In der Methoden-Signatur spezifiziert
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 26
- 27. Beispiel für Fehler
• Die folgende Klasse produziert Failure und Error
public class FailMyMathTest {
@Test
public void mal2Test() {
assertEquals(-1, mal2(-1));
} Failure
@Test
public void fehler1() {
throw new RuntimeException("!");
} Error
@Test
public void fehler2() throws SQLException {
throw new SQLException("!");
} Error
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 27
- 29. Zusicherungen mit assertX
• Behauptung / Zusicherung
• Das Ergebnis eines Tests liefert bestimmten Wert
assertEquals( 0 , MyMath.mal2(0) );
assertEquals( -2 , MyMath.mal2(-1) );
assertEquals( 4 , MyMath.mal2(2) );
Erwartungswert tatsächlicher
• Wenn ungleich, wird AssertionFailedError ausgelöst.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 29
- 30. Zusicherungen mit assertX
• Statische Funktionen in der Klasse Assert
• Methoden Assert.assert<BEDINGUNG>().
• True: Wahrheit
• False: Unwahrheit
• Null: Wert gleich Null
• NotNull: Wert ungleich Null
• Same: Referenz stimmt überein
• NotSame: Referenz stimmt nicht überein
• Equals: Ruft Object.equals() auf
• ArrayEquals: Gleichheit von Arrays
• Vorsicht bei Double[] oder Float[]
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 30
- 31. Zusicherungen mit assertX
• Gleitkommaarithmetik ist ungenau
• Bei Float und Double ist ein Epsilon-Interval oft notwendig
• assertEquals(0.33, 1/3d, 0.01);
• Andere Möglichkeit
• assertTrue(Math.abs(0.33 - 1/3d) <= 0.01);
• Java‘s assert
• Java verfügt seit 1.4 über ein assert-Statement
• Option -ea beim Start der JVM notwendig
• assert booleanExpr;
• assert booleanExpr : valueExpr;
• Wirft einen AssertionError
• Unchecked Exception
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 31
- 32. Fehlermeldungen
• Für alle Assertions:
• Optionale Fehlermeldung als erstes Argument
• assertEquals(„Fehlermeldung“, 11, 1+2+3+4)
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 32
- 33. Der Lebenszyklus eines Tests
• Standard im xUnit-Bereich
• 1. Initialisierung
• „Set up“
• Fixture bzw. Kontext
• 2. Ausführung des Tests
• „Excercise“, „execute“
• 3. Überprüfung
• Werden die erwarteten Ergebnisse berechnet?
• 4. Herunterfahren
• „Tear down“
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 33
- 34. Annotationen: Die Basis
• @Test
• Markiert die Test-Methoden
• @Ignore
• Ignoriert eine Methode oder Klasse
• Auch, wenn diese mit @Test annotiert ist
• @Before und @After
• Fixture
• Ausführung vor und nach jeder Testmethode der Klasse
• @BeforeClass und @AfterClass
• Fixture
• Langlaufende Initialisierungen
• Ausführung vor und nach der Testklasse
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 34
- 35. Annotationen: @Test
• @Test markiert die zu testenden Funktionen
• Erwartete Exceptions („error“)
@Test(expected = IndexOutOfBoundsException.class)
public void index() {
new ArrayList<String>().get(2);
}
• Beschränkung der Laufzeit
@Test(timeout = 100)
public void infinity() {
while (true)
;
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 35
- 36. Annotationen: @Ignore
• Ausschluss von Methoden
@Ignore("noch nicht fertig")
@Test
public void something() {
...
}
• Ausschluss von Klassen
@Ignore
public class IgnoreMe {
@Test public void test1() { ... }
@Test public void test2() { ... }
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 36
- 37. Annotationen: @Before und @After
• @Before
• Ausgeführt vor jeder @Test-Methode
• @After
• Ausgeführt nach jeder @Test-Methode
• @BeforeClass
• Ausgeführt nach der Instanzierung der Testklasse
• Vor allen @Test-Methoden
• Methode muss static sein
• @AfterClass
• Ausgeführt nach allen @Test- und @After-Methoden
• Methode muss static sein
• Von allen können beliebig viele angegeben werden
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 37
- 38. Reihenfolge und Vererbung
• Reihenfolge
• Initialisierung der Testklasse
• @BeforeClass-Methoden (auch die geerbten)
• Für alle @Test-Methoden (auch die geerbten)
• Instanzierung der Instanz
• @Before-Methoden (auch die geerbten)
• @Test-Methode
• @After-Methoden (auch die geerbten)
• @AfterClass-Methoden (auch die geerbten)
• Ausführung innerhalb eines Schrittes (rekursiv)
• Die Methoden der Oberklasse in beliebiger Reihenfolge
• Dann die Methoden der Klasse in beliebiger Reihenfolge
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 38
- 39. Beispiel: Reihenfolge und Vererbung
public class HierarchicalBaseTest {
@Before public void beforeBase2() { ... }
@Before public void beforeBase1() { ... }
@BeforeClass public static void beforeBaseClass2() { ... }
@BeforeClass public static void beforeBaseClass1() { ... }
@After public void afterBase1() { ... }
@After public void afterBase2() { ... }
@AfterClass public static void afterBaseClass1() { ... }
@AfterClass public static void afterBaseClass2() { ... }
@Test public void test1() { ... }
@Test public void test2() { ... }
public void test3() { ... }
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 39
- 40. Beispiel: Reihenfolge und Vererbung
• Ausführung ergibt:
Base.BeforeClass 1
Base.BeforeClass 2
Base.Before 1
Base.Before 2
Base.Test 1
Base.After 1 test1
Base.After 2
Base.Before 1
Base.Before 2
Base.Test 2
Base.After 1 test2
Base.After 2
Base.AfterClass 1
Base.AfterClass 2
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 40
- 41. Beispiel: Reihenfolge und Vererbung
public class HierarchicalTest extends HierarchicalBaseTest {
@Before public void before2() { ... }
@Before public void before1() { ... }
@BeforeClass public static void beforeClass2() { ... }
@BeforeClass public static void beforeClass1() { ... }
@After public void after1() { ... }
@After public void after2() { ... }
@AfterClass public static void afterClass1() { ... }
@AfterClass public static void afterClass2() { ... }
@Test public void test1() { ... }
@Test public void test3() { ... } wird
super.test3();
} Kein test2()
}
Ruft Oberklasse
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 41
- 42. Beispiel: Reihenfolge und Vererbung
• Ausführung ergibt: Fortsetzung
Base.BeforeClass 1 After 1
Base.BeforeClass 2 After 2
BeforeClass 1 Base.After 1
BeforeClass 2 Base.After 2
Base.Before 1 Base.Before 1
Base.Before 2 Base.Before 2
Before 1 Before 1
Before 2 Before 2
Test 1 test1 Base.Test 2 test3
After 1 After 1
After 2 After 2
Base.After 1 Base.After 1
Base.After 2 Base.After 2
Base.Before 1 AfterClass 1
Base.Before 2 AfterClass 2
Before 1 test2 Base.AfterClass 1
Before 2 Base.AfterClass 2
Base.Test 3
Test 3
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 42
- 43. Organisation von Tests
• Zu berücksichtigende Faktoren bei der Organisation
• Namenskonventionen
• Klassen und Methoden
• Verzeichnisse und Pakete
• Gruppieren
• Laufzeitdauer
• Abhängigkeiten
• Continuous Integration
• Design von Tests
• Hierarchie von Testklassen
• Gemeinsam genutzer Code
• später ...
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 43
- 44. Namenskonventionen
• Klassen
• Zu testende Klasse
• ClassName
• Testklasse
• ClassNameTest
• Methoden
• „Test behaviour, not methods“ [R05]
• Verben, statt Substantive!
• Nicht wörtlich nehmen, nur ein allgemeiner Ratschlag !
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 44
- 45. Verzeichnisse und Pakete
• Standard
• Zwei Verzeichnisse src und test
• Klasse und Testklasse im gleichen Paket
• protected-Methoden
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 45
- 46. Gruppieren von Tests
• Unterschiedliche Tests
• Unit, Integration, etc.
• Laufzeiten
• Abhängigkeiten
• Datenbank
• Applikationsserver
• Daher
• Gruppieren in TestSuites
• Menge von Testklassen
• Möglichkeiten
• Definition über @SuiteClasses
• Aufruf über Ant‘s <junit>-Task
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 46
- 47. Gruppieren mit @SuiteClasses
• Folgende Klasse definiert eine Suite
• Zwei Testklassen werden ausgeführt
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({HierarchicalTest.class, PointTest.class})
public class Suite1Test {
}
• @RunWith erwartet eine Instanz der Klasse Runner
• Ein Runner ist eine Klasse zum Ausführen von Tests
• @SuiteClasses ist ein Array von Testklassen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 47
- 48. Gruppieren mit Ant
• Der <junit>-Task ruft mit <batchtest> mehrere Tests auf
<junit fork="true">
<classpath refid="path.compile" />
<formatter type="brief" usefile="false" /> Ausgabe
<formatter type="xml" /> als Text
<batchtest todir="build/junit"> und XML
<fileset dir="build/classes">
<include name="**/*Test.class" />
TestSuite
</fileset>
als FileSet
</batchtest>
</junit>
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 48
- 49. Ant: Erzeugen von Reports
• Für jede Testklasse wird eine XML-Datei erzeugt
• Übrigens: Diese Datei ist erweiterbar
• Aus diesen kann ein HTML-Report generiert werden
<junitreport todir="build/junit-report">
<fileset dir="build/unit">
<include name="TEST-*.xml" />
</fileset>
<report format="frames" todir="build/junit-report" />
</junitreport>
• Unterschiedliche Stile und Transformationen sind möglich
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 49
- 52. Beispiel: Exponentielle Glättung
• Beispiel: Exponentielle Glättung
• public class ExponentialSmoothing {
public Double[] smooth(double alpha, Double[] series) {
Double[] result = new Double[series.length];
result[0] = series[0];
for (int i = 1; i < series.length; i++) {
result[i]= alpha*series[i] + (1-alpha)*result[i-1];
}
return result;
}
}
• Fragen:
• Korrekt ? Grenzfälle ?
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 52
- 53. Typische Problemstellungen
• Weiterlaufen nach dem ersten Fehler
• Stoppen nach dem ersten Fehler
• Nur einen Test ausführen
• Nur bestimmte Tests ausführen
• JUnit in eigener JVM ausführen
• Parallele Abarbeitung von Tests
• TestListener & TestRunner
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 53
- 54. Fortgeschrittenes
• In JUnit 4.4 gibt es neue, experimentelle Features
• Wenig Literatur
• Parametrisierte Tests
• Data Driven Testing
• Theorien
• Allgemeine Aussagen
• Invarianten
• Annahmen
• assumeThat() und assumeTrue()
• assertThat() und die Hamcrest-Bibliothek
• Deklarative Beschreibung von Zusicherungen
• „Matcher“
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 54
- 55. Parametrisierte Tests
• Testfälle sollen möglichst viele Fälle abdecken
• Deshalb ist der gleiche Code mit unterschiedlichen Daten
auszuführen
• Data-Driven-Testing
• Runner für parametrisierte Tests
• @RunWith(Parameterized.class)
• Mit @Parameters annotierte Methode
• Definiert eine Collection von Parametern
• Die Parameter werden der Testklasse mit dem
Konstruktor übergeben.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 55
- 56. Parametrisierte Tests
@RunWith(Parameterized.class)
public class ParameterizedMyMathTest {
int param; int expected;
@Parameters public static Collection data() { Testdaten
Collection ps = new ArrayList();
ps.add(new Integer[] {0, 0}); ps.add(new Integer[] {1,2});
ps.add(new Integer[] {-1,-2});
return ps;
}
public ParameterizedMyMathTest(int a, int b) {
this.param = a; this.expected = b; Konstrukt
}
@Test public void test1() {
assertEquals(expected, MyMath.mal2(param));
} Test
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 56
- 57. Annahmen mit assume
• Methoden aus der Klasse Assume
• assumeTrue(booleanExpr);
• assumeThat
• später ...
public class AssumeTest {
int n = -1;
@Test public void t() {
System.out.println("Punkt A");
assumeTrue(n >= 0);
System.out.println("Punkt B");
}}
• Falls die Bedingung nicht zutrifft, wird die Methode
verlassen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 57
- 58. Theorien
• Beim JUnit-Testen wird die Funktionalität anhand von
Einzelfällen spezifiert.
• Keine generellen bzw. allgemeinen Ausssagen!
• Beispiel: Die Quadratwurzel
@Test
public void sqrRootExamples() {
assertEquals(2.0, sqrRoot(4));
assertEquals(3.0, sqrRoot(9));
}
• Aber:
• Die Quadratwurzel hat allgemeine Eigenschaften, die
hier nicht getestet werden.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 58
- 59. Theorien
• Folgende Methode ...
@Theory
public void defnOfSquareRoot(double n) {
assumeTrue(n >= 0);
assertEquals(n, sqrRoot(n) * sqrRoot(n), 0.01);
assertTrue(sqrRoot(n) >= 0);
}
• ... macht die folgenden Aussagen:
• Eine Quadratwurzel ist für nicht-negative Zahlen
definiert.
• Die inverse Funktion ist die zweite Potenz.
• Die Quadratwurzel ist nicht-negativ.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 59
- 60. Theorien
• Die zu testenden Daten werden mit @DataPoint
spezifiziert.
@DataPoint
public static double minusOne = -1.0;
public static double four = 4.0;
public static double five = 5.0;
public static double nine = 9.0;
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 60
- 61. assumeThat, assertThat und
• Deklarative Beschreibung von Annahmen und
Zusicherungen
• assumeThat([value], [matcher statement]);
• assertThat([value], [matcher statement]);
• Beispiele
• assertThat(x, is(3));
• assertThat(x, is(not(4)));
• assertThat(responseString,
• either( containsString("color")).or(
• containsString("colour")));
• assertThat(myList, hasItem("3"));
• Allgemein
• anything, describedAs, is
• Logisch
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 61
- 62. assertThat und Hamcrest
• Objekte
• equalTo, hasToString, instanceOf, isCompatibleType, notNullValue,
nullValue, sameInstance
• Beans
• hasProperty
• Collections
• array, hasEntry, hasKey, hasValue, hasItem, hasItems, hasItemInArray
• Zahlen
• closeTo, greaterThan, greaterThanOrEqualTo, lessThan,
lessThanOrEqualTo
• Text
• equalToIgnoringCase, equalToIgnoringWhiteSpace, containsString,
endsWith, startsWith
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 62
- 63. Trouble-Shooting
• junit.jar wird nicht gefunden
• CLASSPATH
• Bestimmte Tests werden nicht ausgeführt
• Finden der Tests im Klassenpfad
• Hinzufügen zu Suites
• Test verhält sich unerwartet
• Einschränkungen von JUnit beachten !
• Jede Testmethode wird in neuer Instanz gestartet
• Daher kein Zustand in Testklassen
• Reihenfolge unbestimmt
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 63
- 64. Kompabilität zu JUnit 3
• Ausführung von JUnit-4-Tests mit dem JUnit-3-Runner
• Adapter in suite() Methode jeder Klasse
public static junit.framework.Test suite() {
return new JUnit4TestAdapter(MyMathTest.class);
}
• Ausführung von JUnit-3-Tests mit JUnit-4-Runner
• JUnit 4 ist abwärtskompatibel
• Migration von JUnit 3 zu JUnit 4
• Daher meistens nicht notwendig
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 64
- 65. Nachteile von JUnit 4
• Die Entwickler von TestNG sehen ein paar Nachteile bei
JUnit4 [BS08]
• Zustandslosigkeit der Testklassen
• Kein Zustand in der Testklasse zwischen Testmethoden
• Keine Seiteneffekte und Abhängigkeiten
• Einerseits gut, manchmal problematisch
• Workaround mit statische Variablen ist problematisch
• Mehrere Aufrufen bei unterschiedlichen JVMs
• Thread-Sicherheit
• TestNG bietet weitere Möglichkeiten
• Tests überspringen, Gruppierung von Tests
• Später ...
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 65
- 66. JUnit 3
Mein Tip:
Nicht mehr verwenden!
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
- 67. JUnit 3
• JUnit 3 basiert auf Vererbung
• Jede Testklasse muss von TestCase erben
• ABER: Vererbung ist problematisch
• Viele Design-Patterns-Diskussionen
• Nur einfache Vererbung in Java
• Klassen
• TestCase: Für den Testfall
• TestSuite: Eine Sammlung an Testfällen.
• TestRunner: Zum Ausführen der Tests.
• Text basierend
• Swing basierend
•In 4.4 nicht mehr vorhanden, da IDEs bessere haben.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 67
- 68. Die Testfunktionen
• Superklasse TestCase
• Wird abgeleitet und erweitert.
public class MyMathTest extends TestCase {
public void testMal2() { … }
public void testYYY() { … }
public void testZZZ() { … }
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 68
- 69. Die abstrakte Klasse TestCase
public abstract class TestCase implements Test
{
private final String fName;
public TestCase(String name) { fName = name };
public void run() {
setUp();
runTest();
tearDown();
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 69
- 70. Nachteile von JUnit 3
• JUnit3 ist „intrusive“, d.h. macht starke Einschränkungen
• Jede Testklasse muss von TestCase erben
• Nur einfaches Erben in Java
• Methoden
• Müssen spezielle Namen haben
• Wenig flexibel
• Umbennen zeitaufwendig, wenn nur eine Methode
ausgeführt werden soll, kompilieren notwendig
• Haben keine Parameter
• Haben keinen Rückgabewert
• Testen von Exceptions
• Schlecht, da negierte Logik
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 70
- 71. Nachteile von JUnit 3
• Konfiguration mit setUp und tearDown
• nur pro Methode, nicht pro Testklasse
• Keine Abhängigkeiten zwischen Tests
• Wenn ein Test fehlschlägt, brauchen viele nicht
ausgeführt zu werden („skipped tests“)
• Erschwert die Ursachenforschung
• Testklassen mit Zustand nicht möglich
• Workaround mit statischen Variablen ist problematisch
• Thread-Sicherheit
• Nicht möglich, z. B.
• Ausführung nur der fehlerhaften Testklassen
• (Geht bei manchen IDEs)
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 71
- 73. Tests und Design
• Spannungsfeld zwischen Anwendung und Testklassen
• Anwendung
• Abhängigkeiten
•Frameworks, z. B. GUI, Hibernate, Spring
•Applikationsserver und Datenbanken
• OO-Prinzipien
•Kapselung, „encapsulation“
•Singletons, insb. mit finalen Attributen
•Scope
•Schlechte Implementierung: Klassen statt Schnittstellen
•Verwendung von new statt Factory
• Testklassen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 73
- 74. Tests und Design: Anforderungen
• Anforderungen an Tests
• Wartbar, einfach verstehbar
• Stabil gegenüber
• Änderungen am Quellcode, Refaktorisierung
• Zukünftigen Anforderungen
• Anforderungen an die Anwendung
• wie oben
• keine festverdrahteten Abhängigkeiten
• keine „Sichtbarkeitsprobleme“ für die Testklassen
• Oft sind Änderungen für Tests notwendig
• „not all code is testable" [BS08]
• "constant challenge to write easily testable code"
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 74
- 75. Tests und Design: Schnittstellen
• Schlimmster Fehler
• Entwicklung gegen Implementierungen
• Nicht gegen Schnittstellen
public class BadCode1 {
ArrayList<String> list;
public BadCode1() {
list = new ArrayList<String>();
}
}
• Stattdessen die allgemeinste Schnittstelle verwenden
Collection<String> list;
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 75
- 76. Tests und Design: Schnittstellen
• Zweitschlimmster Fehler
• Die konkrete Implementierung im Code festlegen
• Hier ist die ArrayList von Außen nicht änderbar
• Abhängigkeit
• Wenn die Konstruktion sehr lange dauert?
• Und nicht getestet werden soll?
public class BadCode2 {
Collection<String> list;
public BadCode2() {
list = new ArrayList<String>();
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 76
- 77. Tests u. Design: Dependency Injection
• 1. Lösungsmöglichkeit
• Übergabe im Konstruktor
• Entwurfsmuster: Dependency Injection
public class BetterCode1 {
Collection<String> list;
public BetterCode1(Collection<String> list) {
this.list = list;
}
}
• Siehe http://martinfowler.com/articles/injection.html
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 77
- 78. Tests u. Design: Dependency Injection
• 2. Lösungsmöglichkeit
• Übergabe im Setter
• Entwurfsmuster: Dependency Injection
public class BetterCode2 {
Collection<String> list;
public void setList(Collection<String> list) {
this.list = list;
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 78
- 79. Tests und Design: Fabrik / Factory
• 3. Lösungsmöglichkeit
• Entwurfsmuster: Fabrik / Factory
• Übergabe der Fabrik im Konstruktor
• Könnte auch in einem Setter übergeben werden
public class BetterCode3 {
Collection<String> list;
public BetterCode3(Factory factory) {
list = factory.createCollection();
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 79
- 80. Tests und Design: static
• Statische Initialisierungen und finale Attribute sind nicht
austauschbar.
public class BadStaticCode1 {
static final String driver = "org.db.driver";
static final String url = "jdbc:db:host/name"; ...
static {
try {
Class.forName(driver);
Connection con = DriverManager.getConnection(url,
username, password);
Statement stmt = con.createStatement();
stmt.executeQuery("SELECT COUNT(*) FROM XYZ");
} catch (ClassNotFoundException e) {
...
}
• Die Abhängigkeiten sind hier fest verdrahtet
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 80
- 81. Tests/Design: Singletons und static
• Aufgabe: findById() durch Testfunktion zu ersetzen, die
nicht auf die Datenbank zugreift.
public class BadStaticCode2 {
public static Object findById(String id) {
// Hole Objekt aus Datenbank
...
}
public static boolean objectExists(String id) {
return (null != findById(id));
}
}
• Durch Vererbung und Überschreiben nicht möglich !
• Denn: Bei Aufrufen von statischen Methoden wird der
Klassenname fest verdrahtet !
• Möglichkeiten: Bytecode manipulieren oder
Refaktorisieren
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 81
- 82. Refaktorisieren
• Umgestaltung des bestehenden Quellcodes
• Invariante: Semantik / beobachtbares Verhalten
• Verbesserung
• Lesbarkeit, Übersichtlichkeit, Verständlichkeit
• Modularität
• Wartbarkeit, Erweiterbarkeit
• Entfernung von Redundanzen (DRY, „dont repeat
yourself“)
• Integriert in die IDEs
• Kompliziertere sind manuell durchzuführen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 82
- 83. Refaktorisieren
• Häufige Refaktorisierungen
• Umbenennungen
• Verschieben
• Änderung der Signatur einer Methode
• Extraktion einer Methode aus einem Code-Block
• Methodenrumpf einfügen und Methode entfernen
• Verschieben einer Methode die Klassenhierarchie hinauf
oder hinab
• Extraktion einer Schnittstelle aus einer Klasse
• Generalisierung einer Klasse
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 83
- 84. Tests und Design
• Was tun, damit die Tests erfolgreich sind [B02] ?
• Faking it
• Erste schnelle Lösung
• Die Implementierung imitieren
• Methoden geben nur Dummy-Werte zurück
• Triangulation
• Schrittweise Verkleinerung des Lösungsraums durch
Schreiben von Tests
• Schrittweise Generalisierung von mehreren Beispielen
• Obvious Implementation
• Bei kleineren Problemen möglich
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 84
- 85. Design von Tests: Muster
• Allgemeine Richtlinien
• Happy path
• Failure testing
• Java POJOs: Plain Old Java Objects
• Stubs, Fakes und Mocks
• Data Driven Testing
• Nebenläufigkeit / Concurrency
• Dependency Injection
• Performanz
• Im Hinterkopf:
• Spezifikation Code
• Äquivalenz, nicht Implikation !
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 85
- 86. Richtlinie: „Right BICEP“
• Nach [HT03]
• Right
• Ergebnisse gemäß Spezifikation?, „happy path“
• Boundary condition
• Grenzfälle?
• Null, leere Strings, negative Werte etc.
• Inverse operation
• Umkehroperation
• Cross check
• Gegenprobe mit anderen Mitteln
• Error condition
• Fehler provozieren
• Performance
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 86
- 87. Richtlinie für Grenzfälle: „CORRECT“
• Nach [HT03]
• Conformance
• Format, YYYY-MM-DD
• Ordering
• Range
• Wertebereiche, 1..12 für Monat
• Reference
• Beziehungen zu anderen Klassen
• Existence
• Leere Daten, null
• Cardinality
• Time
• Reihenfolge, Nebenläufigkeit
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 87
- 88. Testen von Java POJOs
• Am häufigsten zu testen
• Methoden equals() und hashcode()
• void-Methoden
• Konstruktoren
• Getter und Setter
• Schnittstellen / Interfaces
• JavaBeans
• Collections
• Zusammengesetzte Objekte
• „Compound objects“
• Container
• Aggregation und Komposition in UML
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 88
- 89. Java: equals() und hashcode()
• Wichtig: equals() wird von assertEquals() benutzt
• Für equals() und hashCode() gibt es laut Java-API einen
Vertrag
• Stichwort „design by contract“
• Diese Methoden werden z. B. von Collections verwendet
• equals() muss die folgenden Bedingungen erfüllen
• Reflexiv: a ≡ a
• Symmetrisch: a ≡ b && b ≡ a
• Transitiv: a ≡ b && b ≡ c ==> a ≡ c
• Ergibt sich bei Value-Objekten aus den ersten Beiden
• Für kein a ist a ≡ null
• hashCode()
• Falls a ≡ b, dann a.hashCode() ≡ b.hashCode()
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 89
- 90. Java: equals() und hashcode()
• Einfach, aber arbeitsaufwendig
• Viele Klassen überschreiben equals()
• Einfacher mit EqualsTester von GSBase
@Test
public void equals() {
String a = "Hello";
String b = "Hello";
String c = "Hallo";
new EqualsTester(a, b, c, null);
}
• Zwei gleiche Elemente a und b
• Ein unterschiedliches Element c
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 90
- 91. Java: void-Methoden
• Testen der Seiteneffekte, der Zustandsänderungen
• Vorbedingungen
• Zustand des Objekts / der Klasse
• Aufruf der zu testenden Methode(n)
• Nachbedingungen
• Zustand des Objekts / der Klasse
• Wenn die Seiteneffekte nicht sichtbar sind?
• Refaktorisieren
• Mit Reflektion
• Zugriff auf private Daten und Methoden
• JUnitX hat Hilfsmethoden hierfür
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 91
- 92. Java: Konstruktoren
• Kommt selten vor
• Henne-und-Ei-Problem:
• Ein Objekt ist zum Vergleich notwendig
• Ist Zustand sichtbar ?
• Testen der Attribute über getter() oder public Attribute
• Nicht sichtbar ?
• NICHT: Methoden sichtbar (public) machen !
• Die Kapselung nicht brechen!
• Möglichkeiten
• Neue isValid()-Methode hinzufügen
• Erwartungswerte als Parameter übergeben
•Der Test wird in der Klasse durchgeführt
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 92
- 93. Java: Getter und Setter
• Nur, wenn diese Logik beinhalten
• Validierung
• Berechnete Attribute
• Meistens „too simple to break“
public class TooSimple {
String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getLength() { return name.length(); }
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 93
- 94. Java: Schnittstellen / Interfaces
• Schnittstellen definieren nur die Syntax, keine Semantik
• Problem: Klassen, die Schnittstelle implementieren, sollen
ein bestimmtes Verhalten aufweisen
• Beispiel einer Schnittstelle
public interface IMailer {
public boolean sendMail(String to, String subject, String body);
public List<String> getMails();
}
• Spezifiziertes Verhalten:
• getMails() gibt alle Addressen der bisher gesendeten
Mails zurück
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 94
- 95. Java: Schnittstellen / Interfaces
• Lösung: Spezifikation des Verhaltens in abstrakter
Testklasse
abstract public class AbstractMailerTest {
abstract protected IMailer getMailer();
@Test
public void sendMail() {
int n = getMailer().getMails().size();
getMailer().sendMail("xyz@xyz.xy", "test", "body");
int m = getMailer().getMails().size();
assertEquals(n+1, m);
}
}
• Testklassen der Implementierungen erben sendMail()
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 95
- 96. Java: Schnittstellen / Interfaces
• Testklassen der Implementierungen erben sendMail()
• Und müssen nur die getMailer()-Methode implementieren
public class MailerImplTest extends AbstractMailerTest {
private IMailer mailer;
@Override
protected IMailer getMailer() {
if (null == mailer) {
mailer = new MailerImpl();
}
return mailer;
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 96
- 97. Java: JavaBeans
• Auszug aus einem Beispiel
public class MailBean extends Object implements Serializable {
private PropertyChangeSupport propSupport;
private String to, subject, body;
public MailBean() {
propSupport = new PropertyChangeSupport(this);
}
public void setTo(String value) {
String oldValue = to; to = value; Nachricht
propSupport.firePropertyChange("to", oldValue, to);
}
public void addPropertyChangeListener(...) {
propertySupport.addPropertyChangeListener(listener);
}
...
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 97
- 98. Java: JavaBeans
• JavaBean
• Getter und Setter
• Nur, wenn sie Logik beinhalten
• PropertyChange Events (Event Source)
• Eigenen Listener schreiben
• Merkt sich den letzten geänderten Wert
public class Listener implements PropertyChangeListener {
public Object newValue;
@Override
public void propertyChange(PropertyChangeEvent evt) {
newValue = evt.getNewValue();
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 98
- 99. Java: JavaBeans
• Im Test
• Rufen wir einen Setter auf
• Und vergleichen mit dem letzen Wert des Listeners
@Test
public void testFirePropertyChanges() {
Listener lst = new Listener();
bean.addPropertyChangeListener(lst);
bean.setTo("xyz@xyz.xy");
assertEquals("xyz@xyz.xy", lst.newValue);
}
• Die Aufrufe von firePropertyChange sind getestet
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 99
- 100. Java: Collections
• Lösung: equals() benutzen
• Folgende Bedingungen für die Gleichheit nach equals()
• Collection
• Gleicher Typ (List, Set, Map) und gleich nach dem
Folgenden
• List
• Gleiche Elemente an gleicher Position
• Set
• Gleiche Elemente
• Map
• Gleiche Schlüssel und gleiche Werte für jeden Schlüssel
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 100
- 101. Java: Komplexe Objekte
• Klassen haben evtl. viele Attribute A1,...,An
• Zustandsraum
• Menge der unterschiedlichen Instanzen einer Klasse
• Sei Di ist die Anzahl der Instanzen des Attributs Ai
• Größe: D1 * D2 * D3 * ... * Dn
• Problem:
• Kombinatorische Explosion des Zustandraums
• Selbst wenn nur die equals()-Methode getestet werden
soll sind n+3 Instanzen mit dem EqualsTester notwendig
• 2 Gleiche, n Unterschiedliche und 1 Unterklasse
• Im Diasparsoft Toolkit gibt es hier ValueObjectEqualsTest
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 101
- 102. Java: Komplexe Objekte
• Container enthalten andere Objekte und kontrollieren
deren Lifecycle
• In UML: Aggregation
• Problem:
• Der Container soll getestet werden
• Ohne die anderen Objekte zu instanziieren
• Lösung
• Refaktorisieren
• Dependency-Injection
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 102
- 103. Stubs, Fakes und Mocks
• Beim Film:
• Attrappen, Kulissen, Dummys, Doubles, etc.
• Beim Testen
• Das zum Testen notwendige Minimum herstellen
• Wir müssen Schnittstellen und Klassen ersetzen
• Schnittstelle
• Implementieren
• Klasse
• Ableiten
• Problem: finale Klassen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 103
- 104. Stubs, Fakes und Mocks
• Anwendungsgebiete
• Wenn Ausführung zu lange dauert
• Datenbanken
• Applikationsserver
• Simulation von Ereignissen
• Festplatte voll
• Netzwerk ausgefallen
• Wenn Klasse noch nicht implementiert wurde
• Bei nichtdeterministischen Ergebnissen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 104
- 105. Stubs, Fakes und Mocks
• Stub
• Damit das Programm kompiliert
• Ansonsten leer
• Fake
• Gibt künstliche Daten zurück
• Mock
• White-Box
• Annahmen über Interna der Klasse
• "mock objects are not refactoring friendly"
• "test brittleness increases with expectations"
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 105
- 106. Stubs, Fakes und Mocks: Stub
• Stub
• Damit das Programm kompiliert
public class MailerStub implements IMailer {
@Override
public List<String> getMails() {
return null;
}
@Override
public boolean sendMail(String to, String subject,
String body) {
return false;
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 106
- 107. Stubs, Fakes und Mocks: Fake
• Fake
• Gibt künstliche Daten zurück
public class MailerFake implements IMailer {
@Override
public List<String> getMails() {
List<String> ls = new ArrayList<String>();
ls.add("xyz@xyz.xy");
return ls;
}
@Override
public boolean sendMail(String to, String subject,
String body) {
return true;
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 107
- 108. Stubs, Fakes und Mocks: Mock
• Mock
• Implementieren die Schnittstelle, API
• Und das spezifizierte Verhalten
• Methoden werden in der gleichen Reihenfolge aufgerufen
•a(), b(), a(), a(), etc.
• Die Anzahl der Methodenaufrufe ist gleich
• Da Mock-Objekte sehr Nahe am API sind
• Sehr abhängig von Änderungen des API
• Wenn z. B. eine Refaktorisierung durchgeführt wird
• Zerbrechlich, „brittleness“
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 108
- 109. Mocks: easyMock
• easyMock
• Generiert Mock-Objekte
• Benötigt Java 5
• Code ist refaktorisierbar
• Mock-Generatoren
• Funktionieren wie ein Rekorder
• Aufzeichnung
•Der erwarteten Methodenaufrufe
•Der Rückgabewerte
• Aufruf des Testcodes
• Vergleich der Erwartung mit dem Ist
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 109
- 110. Mocks: easyMock
@Test public void mockTest() {
IMailer mock = createMock(IMailer.class);
expect(mock.getMails()).andReturn(new ArrayList());
expect(mock.sendMail("xyz@xyz.xy", "Subject",
"Body")).andReturn(true);
expect(mock.getMails()).andReturn(new ArrayList());
replay(mock);
Aufzeichnun
mock.getMails();
mock.sendMail("xyz@xyz.xy", "Subject", "Body");
mock.getMails();
verify(mock);
} Vergleich
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 110
- 111. Mocks: jMock
• Über jMock liest man selten Gutes
• Methodennamen werden als Strings übergeben
• Keine Refaktorisierung
• Erfordert erben von einer Basisklasse
• Anti-Pattern
• Intrusive
• Verkette Aufrufe von Methoden
• Schwierig zu Debuggen
• Erwartungen müssen genau angegeben werden
• Ist nicht so einfach, wie easyMock
• siehe http://www.jmock.org/easymock-comparison.html
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 111
- 112. Data Driven Testing
• Wo können Daten für Tests herkommen?
• Java Properties
• Umgebungsvariablen
• Resource Bundles
• Dateien
• CSV, XML, etc.
• Datenbanken
• In JUnit4 mit parametrisierten Testklassen einfach
durchzuführen
• Das war in JUnit3 nicht so
• Beispielklassen, Templates für die obigen Datenquellen in
der Fachliteratur [R04]
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 112
- 113. Nebenläufigkeit / Concurrency
• Neue Fragestellungen
• Thread-Sicherheit
• „thread-safety“
• Datenstruktur bei gleichzeitigem Zugriff korrekt
• Verklemmungen
• „race-conditions“, „dead-locks“
• Sicherheit
• „safety“
• „nothing bad ever happens“
• Lebendigkeit
• „liveness“
• „something good eventually happens“
• Fairness
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 113
- 114. Nebenläufigkeit: Problemstellung
• Zustand
• Zustand ist die Menge der Attribute / Felder
• Methoden ändern den Zustand, Z -> Z‘
• Die Korrektheit einer Java-Klasse
• Meistens für sequentiellen Zugriff formuliert
• Nicht für gleichzeitigen, parallelen Zugriff
• Problem: nicht atomare Methodenaufrufe
• count++
• a=b+c
• „read-modify-write“
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 114
- 115. Nebenläufigkeit: Zustand
• Zustandsvariablen und die Schwierigkeit des Testens
• „don't share“
• Nur atomarer Zugriff
• Konstant, „immutable“
• Unveränderlich
• Zum Beispiel String
• Veränderlich, Synchronisierung notwendig
• volatile
• synchronized
• Locking protocol
•Sperren, locks
•Gegenseitiger Ausschluss, „mutual exclusion“
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 115
- 116. Nebenläufigkeit: synchronized
• Die Variable count ist veränderlich
• Es gibt „lost updates“ in inc()
public class Unsafe1 {
public int count;
public void inc() { count++; }
synchronized public void inc1() {
count++;
}
public void inc2() {
synchronized (this) {
count++;
}}}
• Wichtig: Locks so schnell wie möglich loswerden
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 116
- 117. Nebenläufigkeit: Atomic
• Möglichkeit für einzelne Attribute
• Atomare Variablen
• in java.util.concurrent.atomic
public class Safe1 {
public AtomicInteger count;
public void inc() {
count.addAndGet(1);
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 117
- 118. Nebenläufigkeit: Thread-Safety
• Durch statistische Auswertung
• Sprich: Wiederholen des Tests bis der Fehler
wahrscheinlich auftritt
• Empirisch
• Notwendig:
• Starten des Tests mit mehreren Threads
• Genügend Aufrufe, damit der Fehler auftritt
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 118
- 119. Nebenläufigkeit: Weitere Punkte
• Einfache Lösung:
• "Thread confinement"
• Beispiele: Swing und Eclipse SWT
• Swing und SWT sind nicht thread-sicher
• Alles läuft in einem separatem Thread
• Verantwortung des Programmierers
• Swing
Runnable doWorkRunnable = new Runnable() {
public void run() { doWork(); }
};
SwingUtilities.invokeLater(doWorkRunnable);
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 119
- 120. Dependency Injection
• Frameworks für einfachere Konfiguration
• (als die ganzen Setter bzw. Konstruktoren aufzurufen)
• Produktivanwendung
• Die richtigen Klassen
•JDBC, JMS, etc.
• Bei Tests
• Stubs, Fakes und Mocks
• Beispiele
• EJB 3.0
• Spring
• Seam
• Guice
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 120
- 121. Performanz- und Lasttests
• Performancetests
• Absolut
• Zeitabschätzung mit oberer Schranke
• Relativ
• Messen der Zeit für n=10, dann für n=100
• Abschätzung nach O(n)-Notation + konstanter Faktor
• Lange Laufzeiten
• Daher von den Unit-Tests separieren
• Frameworks
• JUnitPerf
• JMeter
• The Grinder
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 121
- 122. Performanz: Absolut
• Absolut
• Zeitabschätzung mit oberer Schranke
@Test(timeout = 1000)
public void absolute() {
run(100);
}
• Nachteile
• Abhängig von Hardware
• Abhängig von Auslastung
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 122
- 123. Performanz: Relativ
• Relativ
• Messen der Zeit für n=k, k=10000
• Dann für n=k*10
• Abschätzung nach O(n)-Notation + konstanter Faktor
@Test public void relative() {
Date d1 = new Date();
run(10000); Date d2 = new Date();
run(100000); Date d3 = new Date();
long ms1 = d2.getTime() - d1.getTime();
long ms2 = d3.getTime() - d2.getTime(); Zeit
assertTrue("Performance", ms1000 < ms100 * 10);
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 123
- 124. JUnitPerf
• Erweiterung von TestCase
• Daher JUnit 3.8
• Dekorator-Pattern
• erlaubt die Erweiterung bestehender Tests
• unabhängig von bestehenden Tests
• TimedTest
• misst die vergangene Zeit
• maximale Zeit kann angegeben werden
Test case = new MyTest("testMethod");
Test timedTest = new TimedTest(case, 1000);
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 124
- 125. JUnitPerf
• LoadTest
• simuliert mehrere User und Iterationen
• Beispiel
• Für 10 Benutzer und 100 Iterationen
• Alle 100 ms ein neue Benutzer
Timer timer = new ConstantTimer(100);
Test case = new MyTest("testMethod");
Test loadTest = new LoadTest(case, 10, 100, timer);
• Die gemessene Zeit ist
• setUp() + Testmethode + tearDown()
• Kein fully fledged Performance profiling tool
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 125
- 126. JMeter
• Lade und Performanztests für Server
• Web, HTTP, HTTPS
• SOAP
• Datenbanken / JDBC
• LDAP
• JMS
• POP3 (Email)
• Ausführung von Testplänen
• Aufzeichnung von Testschritten
• GUI-Oberfläche
• Keine JUnit-Erweiterung !
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 126
- 127. The Grinder
• Verteilte Test-Framework
• Load-Tests
• Anpassbar an alle Java APIs
• HTTP, SOAP, REST, CORBA, RMI, EJBs, JMS
• Für Entwickler
• Aktuelle Version
• The Grinder 3
• Tests werden in Jython spezifiziert
• Java-Implementierung von Python
• Test von Web- oder EJB-Anwendungen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 127
- 128. Äquivalenz, nicht Implikation
• Beispiel: Binäre Suche in einem Array
• Nach
• Oram, Wilson. „Beautiful Code“, O'Reilly 2007. Kapitel 7
• Gegeben sei ein Array arr von Integern und ein Integer i
• Gesucht
• Die Position von i, falls i enthalten ist
• -1, sonst
• Laufzeitanforderung O(lg n)
• Die erste Version der binären Suche ist von 1946, die
erste Fehlerfreie von 1958.
• Der Korrektheitsbeweis in John Bentley‘s „Programming
Pearls“ macht die Annahme der exakten Arithmetik.
• Daher ist ein Bug bei großen Arrays enthalten.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 128
- 129. Äquivalenz, nicht Implikation
• Die Theorie über die binäre Suche search(arr, i)
• Annahmen „hin“
• search(arr, i) = -1 => arr enthält i nicht
• search(arr, i) = k & k>-1 => arr enthält i an Position k
• Annahmen „her“
• arr enthält i nicht => search(arr, i) = -1
• arr enthält i an Position k => search(arr, i) = k & k>-1
• Performanz
• arr.length = n => #{search(arr, i)} <= 1 + log2 n
• wobei #{} die Anzahl der Arbeitsschritte ist
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 129
- 131. JUnit 3 und JUnit 4
• Erweiterungen
• Die auf JUnit 3 aufsetzen und von TestCase erben
• Können nicht immer in JUnit 4 Klasse benutzt werden
• Möglichkeit:
• JUnit 3 Klasse schreiben
• Und mit JUnit 4 Runner (mit den anderen Tests) aufrufen
• Eventuell gibt es Adapter oder Workarounds
• Im WWW danach suchen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 131
- 133. PMD
• PMD ist ein Werkzeug zur
Quellcodeanalyse.
• Es kann mögliche Fehler, suboptimalen
Code, etc. finden
• Ist mit Regeln konfigurierbar und
erweiterbar
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 133
- 134. Findbugs
• Findbugs analysiert die Qualität des Quellcodes.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 134
- 135. Checkstyle
• Checkstyle analysiert die Code-Qualität.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 135
- 136. JavaNCSS
• JavaNCSS berechnet die Anzahl der reinen Codezeilen.
• Non-commenting source statements
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 136
- 138. Testabdeckung: Grundlagen
• „Überdeckungstest“
• Metrik der Code-Qualität
• Welche Teile des Codes werden beim Test ausgeführt ?
• Granularitäten
• Klasse
• Methode
• Statement
• Block
• Branch/Decision
• Schwierigkeit
• kombinatorische Explosion
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 138
- 139. Testabdeckung: Warnung
• Die Testabdeckung ...
• Sollten NIE als Metrik über die Qualität der Tests oder
des Codes verstanden werden
• Ist nur ein Indikator für Problembereiche
• Kann also nur negative Aussagen machen, keine
positiven
• „designing for coverage is evil“ [BS08]
• Einfache Tests, die immer nur das „richtige“ testen,
ergeben auch 100% Abdeckung
• „coverage exclusion comments“ sind strikt zu vermeiden
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 139
- 140. Testabdeckung: Werkzeuge
• Beispiele
• Kommerziell
• Atlassian Clover
•Ab 1200 $ für Einzelplatzlizenz, $2200 für 10 Benutzer
• JCoverage (Eclipse-Plugin, 3.1 und 3.2)
•19.95 GBP pro Entwickler pro Jahr
• Open Source
• Cobertura
• EMMA
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 140
- 141. Testabdeckung: Arbeitsweise
• Arbeiten durch Modifizierung des Codes
• Methoden zur Sammlung von statistischen Daten
werden vor jede Anweisung eingefügt
• „Instrumentalisieren“
• Möglichkeiten der Code-Änderungen
• Quellcode
• Bytecode
• Oder der Java VM
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 141
- 143. Testabdeckung: Cobertura
• Die Methode createIgnoreBranches wurde nicht getestet
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 143
- 144. Testabdeckung: NetBeans
• Code Coverage Plugin
• Benutzt EMMA, ab Java 6
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 144
- 147. DbUnit
• DbUnit ist ein Testwerkzeug für die Datenbank.
• Testdaten werden in XML-Dateien definiert.
• Damit werden sowohl Fixtures als auch erwartete
Ergebnisse spezifiziert
• Erweitert TestCase, daher JUnit 3
• Das Datenbank-Schema wird in einer DTD gespeichert
<!ELEMENT PREDICTION_GROUP_TYPE EMPTY>
<!ATTLIST PREDICTION_GROUP_TYPE
ID CDATA #REQUIRED
NAME CDATA #IMPLIED
>
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 147
- 148. DbUnit
• Inhalte von Tabellen werden in XML gespeichert
<PREDICTION_GROUP_TYPE ID="1" NAME="Prognosegruppe" />
<PREDICTION_GROUP_TYPE ID="2" NAME="Trendgruppe" />
• DbUnit verfügt über Zusicherungen
public static void assertEquals(ITable expected, ITable actual)
public static void assertEquals(IDataSet expected, IDataSet actual)
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 148
- 149. Allgemeines zum Testen von DB
• Testen auf einer „großen“ Datenbank hat Nachteile:
• Die Performanz ist schlecht.
• Die Entwickler stören sich evtl. gegenseitig
• Jedem Entwickler sein eigenes Schema
• Lösung: In-Memory Datenbank
• HSQLDB
• Derby.
• Die In-Memory DB wird einmal initialisiert und kann
schnell für jeden Testfall „frisch“ gemacht werden und
schnell die Testfälle abarbeiten.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 149
- 151. XMLUnit
• XML-Dokumente sind überall
• Zu Testen sind ...
• Konformität, Validierung
• Document Type Definition DTD
• XML Schema Definition (XSD)
• Reihenfolge der Elemente
• Transformationen mit XSLT
• Rudimentäre Lösung
• Vergleich der Elemente mit XPath
• XMLUnit
• Komfortabler
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 151
- 152. Erinnerung: XML
• XML
• Elemente („tags“) und Attribute
• Starttags und Endtags, verkürzter Endtag ‚/>‘
• Hierarchie mit Baumstruktur
• DOM „document object model“
• <project name="Tutorial" default="build">
<target name="build">
<echo message="Hallo Welt!" />
<echo message="Hallo nochmal!" />
</target>
</project>
Elemente Attribute
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 152
- 153. Erinnerung: XML-Baumstruktur
• <project name="Tutorial" default="build">
<target name="build">
<echo message="Hallo Welt!" />
<echo message="Hallo, nochmal!" />
</target>
</project> project
name=“Tutori
al“
target
echo echo
message=“Hallo, Welt“ message=“Hallo,
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 153
- 154. XMLUnit: Möglichkeiten
• XMLUnit kann
• Unterschiede zwischen Dokumenten
• Diff und DetailedDiff
• Gültigkeit („validity“) eines Dokuments
• Validator
• Ergebnis einer XML-Transformation mit XSLT
• Transform
• Ergebnisse von XPath-Ausdrücken
• XpathEngine
• Knoten durch DOM-Traversal ermitteln
• NodeTest
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 154
- 155. XMLUnit: Möglichkeiten
• XMLUnit unterscheidet beim Vergleich
• identisch („identical“)
• similiar
• „recoverable“
• auch selbst definierbar durch DifferenceListener
• different
• „unrecoverable“
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 155
- 156. XMLUnit
• Unterschiede werden in Diff-Objekten gespeichert.
@BeforeClass
public static void setUp() {
XMLUnit.setIgnoreWhitespace(true);
}
@Test
public void textsAreIdentical() throws SAXException, IOException {
Diff diff = new Diff(XmlProducer.getXml1(),
XmlProducer.getXml2());
assertTrue(diff.toString(), diff.identical());
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 156
- 158. Rich Clients-Frameworks für Java
• Viele Frameworks
• Swing und Abstract Windowing Toolkit (AWT)
• Eclipse Standard Windowing Toolkit (SWT)
• Eclipse Rich Client Platform (RCP)
• Basiert auf SWT
• NetBeans
• Zukünftige Entwicklungen
• Swing Application Framework (JSR 296)
• JavaFX
• Spring richclient
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 158
- 159. Rich Clients-Frameworks für Java
• Aspekte eines GUI-Frameworks
• Kleinere Aufgaben und Utilities
• Validierung von Benutzereingaben
• Formatierung von Ausgaben
• Layout und Anzeige der graphischen Elemente
• Die eigentliche Hauptaufgabe der GUI
• Tip: Nur automatisiert testen, wenn unbedingt nötig
•Beispiel: Bibliothek von Widgets
• Interaktion mit dem Benutzer
• Ereignisse, Events
• Zustand und zustandsbasierte Änderungen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 159
- 160. Testen von Rich Clients
• Schwierig zu Testen
• Abhängigkeit von GUI-Klassen
• GUI reagiert nur auf Ereignisse
• Die GUI-Elemente sind für die Tests nicht ohne weiteres
sichtbar
• Manche Tools blockieren den Rechner
• Struktur der Oberfläche ändert sich während der
Entwicklung oft
• Einfachste Lösung
• GUI nur zur Darstellung
• Den Code in der GUI auf ein Minimum reduzieren
• Keine Logik in die GUI
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 160
- 161. MVC und Präsentationsmodell
• Entwurfsmuster „Model-View-Controller“
• Model: Datenmodell
• View: Darstellung (GUI)
• Controller: Logik / Steuerung
View Controller
Model
• Es gibt viele kleinere Variationen
• Leichte Unterschiede zwischen Web- und Rich-Clients
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 161
- 162. MVC
• Bei Swing
• View und Controller vereint bzw. eng-gekoppelt
• Verursacht beim Testen Schwierigkeiten
• Controller kann nicht separat getestet werden
View Controller
Model
• Trennung
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 162
- 163. Neuere Lösung: Presentation-Model
• Presentation Model
• Kein Zustand im GUI
• Da schwierig in Tests an den Zustand heranzukommen ist
• Enthält die Daten und Logik der Oberfläche
• Data Binding zwischen GUI und Präsentationsmodell
• http://martinfowler.com/eaaDev/PresentationModel.html
• Ähnlich
• Model-View-Presenter
• Supervising Controller
• Passive View oder „The Humble Dialog Box“
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 163
- 164. Data Binding
• Für jedes GUI-Element, das vom Benutzer geändert
werden kann gibt es ein Modell-Element
• Problem
• Synchronisierung zwischen beiden
• Validierung von Eingaben
• Data Binding Frameworks
• Eclipse Data Binding (vorher JFace Data Binding)
• JGoodies
• Beans Binding (JSR 295)
• Das Präsentationsmodell kann mit JUnit getestet werden
• Ist noch ein relativ neues Thema.
• Noch nicht in voller Breite unterstützt
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 164
- 165. Testen von GUIs
• Testing-Frameworks müssen die folgenden Aufgaben
unterstützen
• Finden von Komponenten in der Hierarchie
• Absolute und relative Angaben
•Finde den Knopf mit dem Namen „Ok“
•Finde die dritte Zeile in einer Tabelle
• Programmatisch die GUI manipulieren
• Buttons klicken
• Elemente auswählen
• E-i-n-g-a-b-e-n machen
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 165
- 166. Testen von GUIs
• Viele Frameworks und Tools
• Siehe http://www.testingfaqs.org/t-gui.html
• Open Source
• java.awt.robot
• Abbot (Swing, AWT, SWT, TestNG)
• Jemmy
• Wird auch vom NetBeans-Team genutzt
• JFCUnit
• Pounder
• UiSpec4J
• GSBase
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 166
- 167. Beispielanwendung
• Der Celsius-zu-Fahrenheit-Umwandler aus dem Java-
Web-Tutorial
• Swing-Komponenten
• JFrame
• JTextField
• Eingabe
• JLabel
• Celsius
• JButton
• Zum Konvertieren
• JLabel
• Ausgabe des Ergebnisses
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 167
- 168. Jemmy
• Im Rahmen von NetBeans entstanden
• API für den Zugriff auf die Interna von Swing
• Hängt sich in die Ereignisverarbeitung von Swing ein
• Ortet Komponenten anhand der Events
• Operatoren
• Zugriff auf die Swing-Elemente
• Typisches Vorgehen beim Testen
• Man erstellt einen JFrame
• Addiert die zu testenden Komponente
• Initialisiert den Zustand
• Änderung des Zustands
• Kontrolle des Ergebnisses
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 168
- 169. Jemmy: Beispiel
• Test des Celsius-zu-Fahrenheit-Umwandlers
public class Jemmy1Test {
JFrame frame;
JFrameOperator frameOp;
@Before public void setUp() {
frame = new CelsiusConverterGUI();
frame.setVisible(true);
frameOp = new JFrameOperator(frame); }
@After public void tearDown() {
frame.dispose();
frameOp.dispose(); }
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 169
- 170. Jemmy: Beispiel
• Die Test-Methode
• Suchen der Elemente und Eingabe machen
• Knopf drücken
• Ergebnis vergleichen
@Test
public void runApplication() {
JTextField textField =
JTextFieldOperator.findJTextField(frame, chooser);
textField.setText("1234");
JButton button = JButtonOperator.findJButton(frame, chooser);
button.doClick();
JLabel label = JLabelOperator.findJLabel(frame, chooser, 1);
assertEquals("2253 Fahrenheit", label.getText());
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 170
- 171. Jemmy: Beispiel
• Zum Suchen von Elementen in der Hierarchie der GUI
werden ComponentChooser verwendet
• Der einfachste gibt das erste Element zurück
@Test
ComponentChooser chooser = new ComponentChooser() {
public boolean checkComponent(Component arg0) {
return true;
}
public String getDescription() {
return "";
}
};
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 171
- 173. Testen von Web-Anwendungen
• Arten
• Statische Webseiten
• Dynamische Webseiten
• JSP, Velocity
• Frameworks
• Struts, JSF, Grails
• Auch Web-Anwendungen benutzen MVC
• Geschäftslogik sollte in POJOs implementiert sein
• Kann damit unabhängig getestet werden
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 173
- 174. Testen von Web-Anwendungen
• Client
• Browser
• „Makro-Rekorder“
•Aufzeichnen von Benutzerinteraktionen
•Wiederabspielen
• Browser-Emulatoren
• Simulieren Web-Browser
• Machen Zustand zum Testen zugänglich
• Server
• Im Container/Server
• Leichtgewichtige bzw. simulierte Container
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 174
- 175. Testen von Web-Anwendungen
• Viele Frameworks und Tools
• http://java-source.net/open-source/web-testing-tools
• Frameworks
• Selenium
• HttpUnit
• HtmlUnit
• Canoo Web Test
• Apache Shale
• StrutsTestCase (veraltet, nur Struts 1.2 und 1.3)
• JSFUnit
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 175
- 176. Beispielanwendung
• Das „Hallo-Welt“ der Webanwendungen
Start
Eingabe
Ausgabe
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 176
- 177. Beispielanwendung
• Datei index.jsp
<%@page contentType="text/html" ageEncoding="UTF-8"%>
<html>
<body>
<form action="show.jsp" id="eingabe"> Form
<input type="text" name="eingabefeld" size="24">
<input type="submit" name="senden">
</form>
</body>
</html>
• Stellt eine Eingabefeld dar
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 177
- 178. Beispielanwendung
• Datei show.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<html>
<body> id
<p> Die Eingabe war:
<div id="ausgabe">'<%= request.getParameter("eingabefeld")%>'</
div>
</p> JSP
</body>
</html>
• Bei Aufruf von
http://localhost:8080/WebApp1/show.jsp?eingabefeld=Hallo
• wird „Hallo“ ausgegeben
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 178
- 179. HttpUnit testet Web-Applikationen
• HttpUnit simuliert einen Web-Client
• Kann Requests senden und Responses empfangen
• Unterstützt verschiedene Authentisierungen
• Unterstützt Cookies
• Werden oft zur Speicherung von Zuständen benutzt
• JavaScript
• Unterstützt Weiterleitung von Seiten
• Wird von Frameworks, wie z. B. Struts verwendet
• Der Status eines Web-Clients kann ermittelt und
ausgewertet werden.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 179
- 180. HttpUnit
• HttpUnit unterstützt u. a. die folgenden Klassen
• WebConversation
• Eine Web-Verbindung
• WebRequest
• GET oder POST zu einer URL
• WebResponse
• Die Antwort des HTML-Servers
• WebForm
• Eine HTML-Form
• HTMLElement
• Ein HTML-Element, z. B. <p>Beispiel</p>
• Funktionen zum Suchen von Elementen usw.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 180
- 181. HttpUnit: JUnit4
• Wir überprüfen dieses mit einem Test.
public class HttpUnitTest {
final private String text = "Hallo Welt!";
@Test public void test1() throws IOException, SAXException {
WebConversation conv = new WebConversation();
String url = "http://localhost:9080/WebApp1/index.jsp";
WebRequest req = new GetMethodWebRequest(url);
WebResponse res = conv.getResponse(req); 1. Seite
WebForm form = res.getFormWithID("eingabe");
req = form.getRequest();
req.setParameter("eingabefeld", text); Ausfüllen
res = conv.getResponse(req);
HTMLElement elem = res.getElementWithID("ausgabe");
assertEquals("'" + text + "'", elem.getText());
}}
2. Seite
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 181
- 182. Selenium IDE
• Makro-Rekorder
• Browser-Erweiterung
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 182
- 183. Selenium IDE
• Die aufgezeichneten Tests lassen sich als JUnit3-Test
exportieren.
public class SeleniumTest extends SeleneseTestCase {
public void setUp() throws Exception {
setUp("http://localhost:9080/examples/jsp/", "*chrome"); }
public void testNew() throws Exception {
selenium.open("http://localhost:9080/examples/jsp/");
selenium.click("//tr[6]/td[2]/a[2]");
selenium.waitForPageToLoad("30000");
... selenium.click("submit");
selenium.waitForPageToLoad("30000");
verifyTrue(selenium.isTextPresent("oranges"));
verifyTrue(selenium.isTextPresent("apples"));}}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 183
- 184. JEE / J2EE
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
- 185. JEE / J2EE
• Frage: Im Server oder Stand-alone
• Problem: Abhängigkeiten
• POJOs sind einfach zu testen
• Integrationstests benötigen den Server
• Sicherheit, Transaktionen, etc.
• Generell:
• Bei EJB3 und Spring einfacher als bei EJB2
• Frameworks (Auszug)
• Apache Cactus
• JUnitEE
• EJB3Unit
• ORMUnit
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 185
- 186. Apache Cactus
• Generelles Framework
• Serverseitiger Code
• Servlets, EJBs, Tag-Bibliotheken
• Schwerpunkt Integrationstests
• Erweiterung von JUnit3
• ServletTestCase
• JspTestCase
• FilterTestCase
• ServletTestSuite
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 186
- 187. JUnitEE
• JUnitEE ermöglicht Unit-Tests auf dem Applikationsserver.
• Es wird ein EAR/WAR/JAR erstellt, das JUnitEE und die
JUnit-Tests enthält
• Dieses wird auf dem Server deployed
• Tests sind per RMI oder über eine Webseite aufrufbar
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 187
- 189. TestNG
• Aus Unzufriedenheit mit JUnit3 entwickelt [BS08]
• Diente als Vorbild für Neuerungen in JUnit4
• Basiert auf Annotationen
• Java 5
• Java 4 mit JavaDoc-Annotationen möglich
• Ziel
• Unit-, Integrations- und System-Tests
• Flexible Konfiguration von Tests
• Gruppierungen
• Tests überspringen
• Tests auf anderen Maschinen ausführen
• Parallele Ausführung von Tests
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 189
- 190. TestNG: Die Annotationen
• Annotieren der Methoden wie bei JUnit 4 mit
• @Test
• Flexibler als bei JUnit4
• Abhängigkeit von Gruppen (dependsOnGroups, groups)
• Abhängigkeit von Methoden (dependsOnMethods)
• Mehrmalige Aufrufe in mehreren Threads
• invocationCount, threadPoolSize
• successPercentage
• Parametrisierte Tests / Data-Driven Tests
• dataProvider, dataProviderClass
• Testmethoden dürfen Argumente und Rückgabewerte
haben
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 190
- 191. TestNG: Die Annotationen
• Before- und After-Annotationen
• @BeforeSuite, @AfterSuite
• Testsuite
• @BeforeGroups, @AfterGroups
• Gruppe
• @BeforeClass, @AfterClass
• Klasse (wie bei JUnit 4)
• @BeforeTest, @AfterTest
• Test
• @BeforeMethode, @AfterMethod
• Vor jeder Methode (wie bei JUnit 4 @Before und @After)
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 191
- 192. TestNG: Die Annotationen
• @DataProvider
• Erzeugt Daten für eine Test-Methode
• @Factory
• Methode, die Tests erzeugt
• @Parameters
• Beschreibt die Parameter der Testmethode
• Testmethoden dürfen Parameter haben
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 192
- 194. Akzeptanztests
• Erweiterung des TDD auf Akzeptanztests [K07]
• Acceptance TDD
• User Story als Spezifikation
• Wer macht was wann und warum
• „power of storytelling“
• Kunde kann in eigener Sprache formulieren
• Deklarativ, nicht operationell
• Akzeptanztests werden mit dem Kunden geschrieben
• HTML, Excel, Word-Dokumente
• Anforderungen in tabellarischer Form
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 194
- 195. Fit - Framework for Integrated Test
• Spezifikation in HTML-Dateien
• Vorteil: Fachabteilung, „executable specification“
• Java-Klasse fit.CalculateCredit ist Fixture
• Attribute: months, reliable, balance
• Methoden: allowCredit(), creditLimit()
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 195
- 196. Fit: Fixture
public class CalculateCredit extends fit.ColumnFixture {
public int months;
public boolean reliable;
public double balance;
private Credit credit = new Credit();
public boolean allowCredit() {
return credit.allowsCredit(months, reliable,balance);
}
public double creditLimit() {
return credit.limit(months,reliable,balance);
}
}
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 196
- 197. Fit: Ergebnis
• Ergebnis
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 197
- 198. Fit: Weiteres
• Fixtures
• ColumnFixture
• Abbildung von Spalten der Testdaten zu Attributen der
Testklassen
• Eine pro spezifizierter Tabelle
• RowFixture
• Flexible und anpassbare Interpretation von Zeilen aus der
Datenbank
• ActionFixture
• Interpretiert Zeilen der Datenbank als Kommandos
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 198
- 199. FitNesse
• Front-End für Fit
• Kollaborative Software-Entwicklung
• Acceptance Testing Framework
• Wiki
• Web Server
• Benutzt Fit
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 199
- 201. Bücher über JUnit 3
• [MH03]
• Vincent Massol, Ted Husted. JUnit in Action.
Manning. 2003.
• [R04]
• J. B. Rainsberger. JUnit Recipes. Manning.
2004.
• [HT03]
• Andy Hunt, Dave Thomas. Pragmatic Unit
Testing. Pragmatic Programmers, LCC.
2003.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 201
- 202. Bücher über TDD
• [B02]
• Kent Beck. Test-Driven Development. By
Example. Addison-Wesley. 2002.
• [K07]
• Lasse Koskela. Test Driven. Practical TDD
and Acceptance TDD for Java Developers.
Manning. 2007.
• [M07]
• Gerard Meszaros. xUnit Test Patterns:
Refactoring Test Code. Addison-Wesley.
2007.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 202
- 203. Bücher über JEE
• [BS08]
• Cedriv Beust, Hani Suleiman. Next
Generation Java Testing: TestNG and
Advanced Concepts. Addison-Wesley. 2008.
• [R06]
• Chris Richardson. POJOs in Action.
Manning. 2006
• [F04]
• Michael Feathers. Working Effectively with
Legacy Code. Prentice Hall. 2004.
© 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 203
Hinweis der Redaktion
- OPT evtl. Diagram Tiefe und Breite
- lib/junit-4.4.jar:build/classes:../JUnit-Base/build/junit-schulung-base.jar
- Assert ist in Java 1.4 bereits enthalten
- TODO Reihenfolge der Ausf&#xFC;hrung
- TODO Running Fortgeschritten
Einzelne mit <test>
- TODO
- brittleness Br&#xFC;chigkeit, Spr&#xF6;digkeit, Zerbrechlichkeit, Morschheit
- Zustandslos .NET ?
- TODO Warnung, dass theo nicht m&#xF6;glich
- TODO
- TODO nanoTime
- TODO
- TODO 1.1 lassen weg Fehlalarm
- TODO Webseiten URLS
- TODO