• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Test-Driven-Development mit JUnit 4
 

Test-Driven-Development mit JUnit 4

on

  • 8,941 views

Schulung über die testgetriebene Software-Entwicklung mit dem Schwerpunkt JUnit 4.

Schulung über die testgetriebene Software-Entwicklung mit dem Schwerpunkt JUnit 4.

Statistics

Views

Total Views
8,941
Views on SlideShare
8,737
Embed Views
204

Actions

Likes
5
Downloads
1
Comments
0

6 Embeds 204

http://dinkla.net 99
http://www.slideshare.net 37
http://www.dinkla.net 35
http://www.dinkla.com 28
http://dinkla.com 4
http://translate.googleusercontent.com 1

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • 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ührung
  • TODO Running Fortgeschritten <br /> Einzelne mit
  • 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

Test-Driven-Development mit JUnit 4 Test-Driven-Development mit JUnit 4 Presentation Transcript

  • Schulung „Testgetriebene Entwicklung mit JUnit 4“ © 2008 - 2009 Jörn Dinkla joern@dinkla.com http://www.dinkla.com © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • Überblick © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • Ü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
  • Grundlagen des Testens © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • JUnit 4 © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • 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
  • 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
  • JUnit4: Ant-Integration • Integration in Ant • <junit> und <junitreport> Tasks • Später mehr ... © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 25
  • 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
  • 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
  • Beispiel für Fehler • NetBeans • Eclipse © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 28
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • Ant: Beispiel eines Reports © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 50
  • Continuous Integration • JUnit ist z. B. in Hudson integriert © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 51
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • JUnit 3 Mein Tip: Nicht mehr verwenden! © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • 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
  • 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
  • Tests und Design © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • Ä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
  • Ä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
  • Erweiterungen von JUnit © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • Nützliche Zusatzprogramme © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • Findbugs • Findbugs analysiert die Qualität des Quellcodes. © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 134
  • Checkstyle • Checkstyle analysiert die Code-Qualität. © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 135
  • JavaNCSS • JavaNCSS berechnet die Anzahl der reinen Codezeilen. • Non-commenting source statements © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 136
  • Testabdeckung © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • 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
  • Testabdeckung: Cobertura • Ändert den Bytecode © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 142
  • Testabdeckung: Cobertura • Die Methode createIgnoreBranches wurde nicht getestet © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 143
  • Testabdeckung: NetBeans • Code Coverage Plugin • Benutzt EMMA, ab Java 6 © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 144
  • Testabdeckung: NetBeans © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 145
  • DbUnit © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • XMLUnit © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • Rich Clients © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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
  • Web-Anwendungen © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • Beispielanwendung • Das „Hallo-Welt“ der Webanwendungen Start Eingabe Ausgabe © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 176
  • 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
  • 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
  • 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
  • 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
  • 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
  • Selenium IDE • Makro-Rekorder • Browser-Erweiterung © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 182
  • 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
  • JEE / J2EE © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • TestNG © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • 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
  • Akzeptanztests © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • Fit: Ergebnis • Ergebnis © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 197
  • 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
  • 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
  • Referenzen © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com
  • 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
  • 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
  • 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
  • Webseiten Hauptseite http://junit.org/ JUnit FAQ http://junit.sourceforge.net/doc/faq/faq.htm JCoverage http://www.jcoverage.com/ Code Coverage Für NetBeans http://codecoverage.netbeans.org/ Testabdeckung EMMA http://emma.sourceforge.net/ Cobertura http://cobertura.sourceforge.net/ JUnitPerf http://www.clarkware.com/software/JUnitPerf.html Performance JMeter http://jakarta.apache.org/jmeter/index.html The Grinder http://grinder.sourceforge.net/ Fit http://fit.c2.com/ Akzeptanztests FitNesse http://www.fitnesse.org/ Selenium http://selenium.openqa.org/ HttpUnit http://httpunit.sourceforge.net/ Web Apache Shale http://shale.apache.org/shale-test/index.html HTMLUnit http://htmlunit.sourceforge.net/ Jemmy Module Für NetBeans http://jemmy.netbeans.org/ GUI Abbot http://abbot.sourceforge.net/doc/overview.shtml Jakarta Cactus http://jakarta.apache.org/cactus/ JEE JUnitEE http://www.junitee.org/ Jester http://jester.sourceforge.net/ Mutation Testing Jumble http://jumble.sourceforge.net/ jMock http://www.jmock.org/ Mocks EasyMock http://www.easymock.org/ GSBase http://gsbase.sourceforge.net/ Hamcrest http://code.google.com/p/hamcrest/ JUnitX http://www.extreme-java.de/junitx/ Sonstige JUnit-Addons http://sourceforge.net/projects/junit-addons DbUnit http://www.dbunit.org/ XMLUnit http://xmlunit.sourceforge.net/ © 2008 - 2009 Jörn Dinkla, http://www.dinkla.com 204