© Holger Röder Winter 2008/2009 Programmentwicklung se Java: Kapitel 6 Programmentwicklung in Java: Javadoc & JUnit Programmentwicklung WS 2008/2009 Holger Röder [email protected] © Holger Röder Winter 2008/2009 Programmentwicklung se Überblick über Kapitel 6 Code-Dokumentation mit Javadoc Einführung in Javadoc Javadoc-Kommentare Javadoc-Tags Erstellung der HTML-Dokumentation Unit-Tests mit dem JUnit-Framework Unit-Tests in Java JUnit am Beispiel Testauswertung, Vor- und Nachbereitung von Testfällen Ausführung von JUnit-Testfällen, Integration in Eclipse Mock-Objekte 2 © Holger Röder Javadoc ist ein Code-Dokumentationswerkzeug, das aus speziellen Kommentaren im Java-Code eine API-Dokumentation im HTML-Format erzeugt. Javadoc wird von Sun entwickelt und ist Bestandteil der Java SE. Die offizielle Java API-Dokumentation wird mit Javadoc erstellt. Programmentwicklung Winter 2008/2009 Javadoc se 3 © Holger Röder Winter 2008/2009 Programmentwicklung se Javadoc-Kommentierung Die Informationen, die von Javadoc in die Dokumentation aufgenommen werden sollen, müssen im Java-Quellcode als JavadocKommentare angegeben werden: /** ... */ Einzelne Parameter, Rückgabewerte etc. werden innerhalb dieser Kommentare über Javadoc-Tags dokumentiert: @param, @return etc. public class Personenliste { /** Javadoc* Liefert die Personen zurück, die am Kommentar * angegebenen Datum im Jahr Geburtstag haben. * Kommentar für jeden Parameter * @param monat Geburtsmonat der Methode * @param tag Geburtstag * @return Liste der Geburtstagskinder; leere Liste, falls * keine Person an diesem Tag Geburtstag hat Kommentar für */ Rückgabewert public List<Person> getGeburtstagskinder(int monat, int tag) { ... // Implementierung } } 4 © Holger Röder /** * Liefert die Personen zurück, die am * angegebenen Datum im Jahr Geburtstag haben. * * @param monat Geburtsmonat * @param tag Geburtstag * @return Liste der Geburtstagskinder; leere Liste, falls * keine Person an diesem Tag Geburtstag hat */ Programmentwicklung Winter 2008/2009 Javadoc-Kommentierung (2) se 5 © Holger Röder Winter 2008/2009 Programmentwicklung se Übersicht: Wichtige Javadoc-Tags Javadoc-Tag Beschreibung @author name-text Adds an „Author“ entry with the specified name-text to the generated docs when the -author option is used. @deprecated deprecated-text Adds a comment indicating that this API should no longer be used (even though it may continue to work). @exception class-name description The @exception tag is a synonym for @throws. @param parameter-name description Adds a parameter with the specified parameter-name followed by the specified description to the "Parameters" section. @return description Adds a „Returns“ section with the description text. @see reference Adds a „See Also“ heading with a link or text entry that points to reference. @since since-text Adds a „Since“ heading with the specified since-text to the generated documentation. @throws classname description Adds a „Throws“ subheading to the generated documentation, with the class-name and description text. @version version-text Adds a „Version“ subheading with the specified versiontext to the generated docs when the -version option is used. Quelle: Sun (http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/javadoc.html) 6 © Holger Röder Winter 2008/2009 Erstellung der HTML-Dokumentation Manuelle Ausführung von Javadoc: javadoc [options] [packagenames] [sourcefiles] [@files] Einzelne Klasse: javadoc -d apidoc Personenliste.java Paket: javadoc -d apidoc pe.doctest Die Aufrufe erzeugen im Zielverzeichnis apidoc die Dokumentation für die Klasse bzw. das Paket. Programmentwicklung In Eclipse: Über Project Æ Generate Javadoc… se Javadoc generiert standardmäßig verschiedene HTML-Dateien, Stylesheets etc. im angegebenen Zielverzeichnis. Startseite der generierten API-Dokumentation: index.html 7 © Holger Röder Winter 2008/2009 Programmentwicklung se Javadoc – Details Javadoc-Kommentare können mit HTML-Tags formatiert werden: /** * Liefert die Personen zurück, die am <strong>angegebenen Datum * </strong> im Jahr Geburtstag haben.<br /><br /> * Aufruf-Beispiel: <code>getGeburtstagskinder(4, 11); </code> */ Javadoc ist nicht auf die Erzeugung von HTML-Dateien beschränkt. Die Verarbeitung der Javadoc-Kommentare erfolgt mit Hilfe sogenannter Doclets. Das Standard-Doclet erzeugt die APIDokumentation im HTML-Format. Es existieren aber auch Doclets für andere Ausgabeformate (XML, DHTML, Framemaker etc.) und Anwendungszwecke (Prüfung der Kommentare, Testfallgenerierung etc.). Darüber hinaus können mit individuellen Taglets auch weitere @Tags verarbeitet werden. 8 © Holger Röder Ludewig/Lichter, 2007: Einzeltest Bei diesem Test werden einzelne, überschaubare Programmeinheiten getestet, je nach verwendeter Programmiersprache also z. B. Funktionen, Unterprogramme oder Klassen. Er wird häufig als Unit-Test bezeichnet. Programmentwicklung Winter 2008/2009 Unit-Tests se 9 © Holger Röder Winter 2008/2009 Programmentwicklung se Unit-Tests in Java Als einzelne, überschaubare Einheiten werden in der Regel Klassen gewählt. Für jede zu testende Klasse (class under test) wird eine eigene TestKlasse erstellt, die möglichst alle (sichtbaren) Methoden der zu testenden Klasse testet. Auch für alle Sonderfälle, Ausnahmefälle und Fehlerfälle einer Klasse oder Methode werden Tests implementiert, die diese abdecken. Die Testfälle werden innerhalb einer Testumgebung durchgeführt, anschließend werden Soll- und Ist-Ergebnisse verglichen. In vielen Fällen werden Unit-Test-Frameworks eingesetzt, die die Entwicklung von Unit-Tests erleichtern, indem sie z. B. die Testtreiber bereitstellen. 10 © Holger Röder Winter 2008/2009 Programmentwicklung se JUnit JUnit ist ein Unit-Test-Framework für Java, das ursprünglich von Kent Beck und Erich Gamma entwickelt wurde und mittlerweile als QuasiStandard für Unit-Tests im Java-Bereich gilt. Motto: „Keep the bar green to keep the code clean!“ Ein farbiger Balken fasst das Ergebnis der Testausführung zusammen: findet der Test keine Fehler, wird der Balken grün; ein roter Balken zeigt Fehler an. Die aktuelle Version JUnit 4 setzt die Neuerungen in Java 5, wie z. B. Annotationen, statische Importe etc., ein (und voraus). http://www.junit.org 11 © Holger Röder Testcode und Anwendungscode sind getrennt. Die Testfälle werden häufig in einer separaten Klassenhierarchie strukturiert. Die einzelnen Testfälle sind unabhängig voneinander, können aber auch zusammengefasst werden. Nach der Ausführung von JUnit wird das Testergebnis sofort angezeigt (grüner bzw. roter Balken). JUnit ist in viele Java-IDEs integriert. Programmentwicklung Winter 2008/2009 Merkmale von JUnit se 12 © Holger Röder Winter 2008/2009 JUnit-Beispiel: Anwendungsklasse Euro Die Anwendungsklasse Euro soll getestet werden. Euro repräsentiert Euro-Geldbeträge als Wertobjekte. public class Euro { final long cents; public Euro(double d) { cents = Math.round(d * 100.0); } Programmentwicklung public double getBetrag() { return cents / 100.0; } se public Euro addiere(Euro e) { return new Euro(getBetrag() + e.getBetrag()); } } 13 © Holger Röder Winter 2008/2009 Programmentwicklung se JUnit-Beispiel: Der erste Testfall JUnit-Testfälle werden in „normalen“ Java-Klassen implementiert. Die Kennzeichnung der Testmethoden geschieht über die Annotation @Test. Für den Vergleich von Soll- und Ist-Resultaten existieren verschiedene assert-Methoden, die statisch importiert werden können. Import der JUnitAnnotation Test import org.junit.Test; import static org.junit.Assert.*; Statischer Import der JUnit-assert-Methoden public class EuroTest { Einzelne Testfälle werden als public-voidMethoden implementiert und mit @Test annotiert. @Test public void betrag() { Euro dreiEuro = new Euro(3.0); assertEquals("getBetrag: ", 3.0, dreiEuro.getBetrag(), 0.001); } } assertEquals vergleicht Soll- und Ist-Resultat (der letzte Parameter gibt die Toleranz bei Gleitkommavergleichen an) Die Ausführung liefert den „grünen Balken“! 14 © Holger Röder Winter 2008/2009 Programmentwicklung se Soll-Ist-Vergleich: assert…()-Methoden Die Klasse org.junit.Assert bietet Vergleichsmethoden, die einzeln oder als Gesamtheit (Assert.*) statisch importiert und in Testfällen verwendet werden können. Vergleich primitiver Typen, z. B.: assertEquals(int expected, int actual) assertEquals(double expected, double actual, double delta) Delta als Toleranz beim Gleitkommavergleich Vergleich von Objekten, z. B.: assertEquals(Object expected, Object actual) Vergleich erfolgt über equals()-Methode assertNotNull(Object object) Bedingungen, z. B.: assertTrue(boolean condition) Alle Methoden existieren auch als Variante mit Fehlermeldung: assertTrue(String message, boolean condition) 15 © Holger Röder Winter 2008/2009 Programmentwicklung se Vor- und Nachbereitung von Testfällen Häufig sind vor oder nach der Ausführung der Testfälle bestimmte Vorbereitungs- oder „Aufräumarbeiten“ notwendig. Sollen bestimmte Methoden vor oder nach jedem Testfall ausgeführt werden, können diese mit @Before oder @After annotiert werden. public class EuroTest { Wird vor jeder @Test-Methode Euro dreiEuro; erneut ausgeführt @Before public void vorbereitung() { dreiEuro = new Euro(3.0); Wichtig: Methode muss public void und parameterlos sein! } @Test public void betrag() { assertEquals(3.0, dreiEuro.getBetrag(), 0.001); } @Test public void addieren() { Euro sechsEuro = dreiEuro.addiere(dreiEuro); assertEquals(6.0, sechsEuro.getBetrag(), 0.001); } } Für die einmalige Ausführung von statischen Methoden vor bzw. nach allen Testfällen in einer Testklasse existieren die Annotationen @BeforeClass und @AfterClass. 16 © Holger Röder Winter 2008/2009 Erwartetete Ausnahmen Wenn eine Ausnahme (Exception) erwartet wird, kann die erwartete Ausnahme (bzw. ihr Class-Objekt) als Attribut expected der @TestAnnotation angegeben werden. @Test(expected=ArithmeticException.class) public void divisionDurchNull() { Division durch Null: hier wird eine int ergebnis = 3 / 0; ArithmeticException erwartet } Programmentwicklung Der Testfall ist erfolglos (grüner Balken), wenn eine Ausnahme auftritt; tritt keine Ausnahme auf, ist der Test erfolgreich (roter Balken). se 17 © Holger Röder Winter 2008/2009 Programmentwicklung se Ausführung von JUnit-Testfällen JUnit-Testfälle können integriert innerhalb der IDE, aber auch manuell über die Kommandozeile ausgeführt werden. Beispiel (Windows): java -cp %JUNIT_HOME%\junit.jar;. org.junit.runner.JUnitCore paket.Klasse JUnit kann in beliebige Java-Programme eingebunden und Testfälle auf diese Weise ausgeführt werden. Die Auswertung (und Anzeige) der Testergebnisse muss in diesem Fall vom aufrufenden Programm durchgeführt werden. import org.junit.runner.JUnitCore; Beliebige Anzahl auszuführender import org.junit.runner.Result; Testklassen public class RunMyTests { public static void main(String[] args) { Result testResult = JUnitCore.runClasses( EuroTest.class, NochEineTestklasse.class); System.out.println("Fehler: " + testResult.getFailureCount()); } } Individuelle Auswertung 18 Eclipse unterstützt JUnit 4 von Haus aus. Die JUnit-Bibliothek kann über die Project Properties eingebunden werden. Programmentwicklung Winter 2008/2009 © Holger Röder JUnit in Eclipse: Einbindung se Wichtig: Version 4 von JUnit einbinden! 19 Über Run As JUnit Test können einzelne Klassen (mit JUnit-Testfällen) oder ganze Pakete mit Testklassen als JUnit-Test ausgeführt werden Programmentwicklung Winter 2008/2009 © Holger Röder JUnit in Eclipse: Ausführung se Beispiel: Testklasse mit insgesamt 7 Testfällen, von denen einer (parseFehler) erfolgreich ist. 20 © Holger Röder Winter 2008/2009 Programmentwicklung se Mock-Objekte Häufig werden bei Unit-Tests Ressourcen benötigt, die bei der Testausführung nicht zur Verfügung stehen, weil sie z. B. noch nicht fertig sind oder die Anbindung zu aufwändig wäre. Typische Beispiele: Datenbank, Server, andere Programmkomponenten etc. In solchen Fällen kann es sinnvoll sein, Mock-Objekte einzusetzen. Mock-Objekte sind Attrappen: sie implementieren die gleiche Schnittstelle wie die „echten“ Objekte und können diese deshalb – für den Test – ersetzen (und simulieren). In der Java API werden Schnittstellen intensiv verwendet. Die Voraussetzungen für Mock-Objekte sind somit häufig gegeben. Tests können somit unabhängig von der Verfügbarkeit der „echten“ Objekte (bzw. Infrastruktur) durchgeführt werden. http://www.mockobjects.com 21 © Holger Röder Mock-Objekte: Beispiel «interface» Datenbank Programmentwicklung Winter 2008/2009 +holePersonen(): List<Person> se In der Anwendung wird nur gegen diese Schnittstelle implementiert MockDatenbank SQLDatenbank +holePersonen(): List<Person> +holePersonen(): List<Person> public List<Person> holePersonen() { List<Person> liste = new ArrayList<Person>(); Person p1 = new Person( "Carl Coder", 27, 4550.0); Person p2 = new Person( "Lisa Lind", 21, 3200.0); liste.add(p1); liste.add(p2); return liste; } Mock-Objekt: simuliert eine Datenbank und liefert einige “sinnvolle” Person-Objekte zurück public List<Person> holePersonen() { ... Connection c = DriverManager.getConnection( "jdbc:derby:TestDB;create=true"); Statement s = c.createStatement(); ResultSet r = s.executeQuery( "SELECT * FROM person"); ... } “Echter” Datenbankzugriff (für den Test evtl. nicht verfügbar, zu teuer o.ä.) 22