Next Generation Testing mit TestNG & Co. Stefan Edlich, Mark Rambow Next Generation Testing mit TestNG & Co. schnell + kompakt Stefan Edlich, Mark Rambow Next Generation Testing mit TestNG schnell + kompakt ISBN-10: 3-939084-02-6 ISBN-13: 978-3-939084-02-0 © 2007 entwickler.press, ein Imprint der Software & Support Verlag GmbH http://www.entwickler-press.de/ http://www.software-support.biz/ Ihr Kontakt zum Verlag und Lektorat: [email protected] Bibliografische Information Der Deutschen Bibliothek Die Deutsche Bibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.ddb.de abrufbar. Korrektorat: Petra Kienle Satz: text & form GbR, Carsten Kienle Umschlaggestaltung: Melanie Hahn Belichtung, Druck und Bindung: M.P. Media-Print Informationstechnologie GmbH, Paderborn. Alle Rechte, auch für Übersetzungen, sind vorbehalten. Reproduktion jeglicher Art (Fotokopie, Nachdruck, Mikrofilm, Erfassung auf elektronischen Datenträgern oder andere Verfahren) nur mit schriftlicher Genehmigung des Verlags. Jegliche Haftung für die Richtigkeit des gesamten Werks kann, trotz sorgfältiger Prüfung durch Autor und Verlag, nicht übernommen werden. Die im Buch genannten Produkte, Warenzeichen und Firmennamen sind in der Regel durch deren Inhaber geschützt. Inhaltsverzeichnis Kapitel 1: Einleitung 9 Kapitel 2: Java Annotations 11 Kapitel 3: TestNG – eine Einführung 3.1 Schnellstart Installation Testfile & Buildfile Testergebnis Assertions nutzen 3.2 JUnit-Tests verwenden 15 16 16 18 21 23 24 Kapitel 4: XML-Konfigurationen 4.1 Die DTD verstehen 4.2 Suite 4.3 Test 4.4 Classes 4.5 Packages 4.6 Methods 4.7 Groups und Runs 4.8 Parameter 25 29 29 31 32 32 33 34 36 Kapitel 5: TestNG Annotations 5.1 @Test Parameter groups Parameter dependsOnGroups und dependsOnMethods Parameter expectedExceptions Parameter dataProvider Parameter alwaysRun 37 37 38 38 40 42 42 schnell + kompakt 5 Inhaltsverzeichnis 5.2 Weitere Parameter 5.3 Aufrufe vor und nach Tests @BeforeClass und @AfterClass @BeforeMethod und @AfterMethod Suite- und Test-Level @BeforeGroup und @AfterGroup Parameter für *Before* und *After* 5.4 Parameterübergabe in den Test 5.5 DataProvider Feste Argumentenanzahl Iteratoren übergeben Parametrisierte DataProvider 5.6 Test Factories 43 45 46 47 47 49 50 51 52 52 53 54 56 Kapitel 6: Code-Coverage 6.1 Cobertura 6.2 Emma 6.3 Clover 59 63 66 68 Kapitel 7: Automatisierung und Buildtools 7.1 Automatisierte Tests 7.2 Ant 7.3 Maven 7.4 CruiseControl 73 74 76 82 92 Kapitel 8: Verwendung von IDEs 8.1 Eclipse 8.2 IDEA 8.3 NetBeans 97 97 100 102 Kapitel 9: JavaEE testen 105 6 Inhaltsverzeichnis Kapitel 10: JTiger 109 Kapitel 11: Vergleich der Test-Frameworks 11.1 Fazit 113 116 Stichwortverzeichnis 117 schnell + kompakt 7 KAPITEL 1 Einleitung Ausgangspunkt dieses Buches war die Tatsache, dass JUnit zwar gut dokumentiert ist, aber mit TestNG ein leistungsfähigeres Werkzeug vorliegt. Zudem ist die Dokumentation in Englisch geschrieben (was nicht jedermanns Sache ist) und sie ist auch nicht so einfach von vorne nach hinten durchzulesen. Die Dokumentation ist wahrscheinlich für Profis angenehm und als HTML-Seite gut zu durchsuchen. Was fehlt, ist aber eine durchgängige Dokumentation, die – wann immer neue Features/Annotations vorgestellt werden – diese auch mit Beispielen erläutert. Es wird daher versucht, einen roten Faden in diesem Buch zu bieten, der jedem Leser einen Schnelleinstieg in die Materie TestNG ermöglicht. Aber natürlich kann dieses kleine Werk nicht so umfangreich sein wie die Online-Dokumentation. Ein „Missing Manual“ ist keinesfalls der Sinn dieses Werks, da Vollständigkeit nur ein umfangreiches Werk oder die Online-Dokumentation bieten kann. Dennoch wagen wir im zweiten Teil den Blick über den Tellerrand hinaus und stellen wichtige Themen, wie andere Testframeworks (JTiger und den Vergleich mit JUnit), vor. Aber auch das Einbinden von TestNG in Test-/Buildtools wie Maven oder schnell + kompakt 9 1 – Einleitung Cruise Control, TestNG und J2EE, IDE Integration und vieles mehr soll dazu beitragen, den Horizont stark zu erweitern. Wir freuen uns über Feedback und wünschen viel Spaß bei der Lektüre! Stefan Edlich ([email protected]) Mark Rambow ([email protected]) 10 KAPITEL 2 Java Annotations Die wichtigste Erleichterung beim Schreiben von Tests entstammt den Java 1.5 Annotations, die auch in TestNG intensiv genutzt werden. Daher hier noch einmal eine kurze Auffrischung der Hintergründe zu Annotations. Bis zu Zeiten von Java 1.4 war klar, dass das Erstellen komplexer Dienste auch viel Code und Konfigurationen erfordert. Das Schreiben von EJBs oder Web Services war lange mit einer Vielzahl von Interfaces oder Deskriptoren behaftet, was aufwändig und fehleranfällig war. Es galt daher schon früh, weitere Informationen in die Java-Datei selbst zu verschieben. Dafür blieb zunächst nur Javadoc übrig. Und so entstanden Tools wie XDoclet, die diese Tags auslesen, verarbeiten und daraus Code, Konfigurationsdateien oder Sonstiges generieren. Dieses Problem wurde für Java im JSR 175 adressiert (.NET kennt hier mit Custom Attributes auch schon länger ein fast gleiches Verfahren). In Java 1.5 (Tiger) wurden dann Annotations eingeführt, die es vorher mit @depricated nur spezifisch gab. Dazu gibt es das Tool apt, welches „Annotation-Prozessoren“ (Code, der com.sun.mirror.* nutzt) liest und ausführt. Annotations können schnell + kompakt 11 2 – Java Annotations aus *.java- und *.class-Dateien oder sogar zur Laufzeit ausgelesen werden. Annotations werden unter Java als Interfaces deklariert. Daher ist auch für TestNG eine Bibliothek zu importieren, die diese Annotations (wie @Test) bekannt macht. Hier ein Beispiel aus der Sun-Dokumentation [1]: public @interface RequestForEnhancement { int id(); String synopsis(); String engineer() default "[unassigned]"; String date(); default "[unimplemented]"; } Wie man sieht, enthält die Deklaration Methoden, die die Elemente/Parameter der Annotation darstellen. Die Methoden selbst enthalten keine Parameter und die Rückgabewerte können nur primitive Typen oder String, Class und enum (und Arrays von diesen Typen) sein. Zusätzlich kann man Default-Werte angeben. Der Aufruf im eigenen Code würde dann so erfolgen [1]: @RequestForEnhancement( id = 2868724, synopsis = "Enable time-travel", engineer = "Mr. Peabody", date = "4/1/3007" ) public static void travelThroughTime( Date destination) { ... } Dies entspricht der Handhabung von Tests in TestNG, wo z.B. ebenfalls als Parameter von @Test Testgruppen angegeben werden können. Aber natürlich können Methoden auch mit Annotations versehen werden, ohne dass der Annotation Elemente über- 12 Java Annotations geben werden. Dies nennt man dann Marker (so wie ein Interface bisher selbst auch ein Marker sein konnte), weil es die Methode einfach nur markiert: @RequestForEnhancement public static void ... Schließlich bleibt zu erwähnen, dass es auch Annotations gibt, die nur ein Element haben. Diese „Single-Element“-Annotations sollten dann nur das Element value in sich tragen: public @interface ConnectionAddress { String value(); } Dann kann man den Namen des Elements und das „=“ weglassen und die Adresse dem Annotation Parser einfach so mitgeben: @Connection Address("192.168.0.2") public class Connector {…} So viel zur Kurzeinführung zum Thema Annotations für TestNG. Interessant ist hier noch, dass am Ende der mittlerweile schon recht betagten Sun-Dokumentation zu lesen ist [1], wie man selbst ein eigenes kleines Testframework bauen kann. Vielleicht kann es Sie ja dazu motivieren, selbst etwas zu entwickeln, das Annotations verwendet. Beispiele wie Hibernate Annotations gibt es zur Genüge. Hinweis Es gibt verschiedene Möglichkeiten, wie Annotations je nach Parameter- und Wertanzahl notiert werden können. Die untenstehende Tabelle gibt daher die wichtigsten Beispiele für die Übergabe von Strings wieder, die in TestNG genutzt werden können. schnell + kompakt 13 2 – Java Annotations Ein Wert @Annotation({„value“}) oder @Annotation(„value“) Mehrere Werte @Annotation({„value1“, „value2“}) Ein Parameter @Annotation(param=“val“) Mehrere Werte @Annotation(param={“val1“,“val2“}) Mehrere Parameter und mehrere Werte @Annotation(param1={„val1“,“val2“,“val3“}, param2={„x1“, „x2“, „x3“}) [1] http://java.sun.com/j2se/1.5.0/docs/guide/language/ annotations.html 14 KAPITEL 3 TestNG – eine Einführung 3.1 Schnellstart 16 3.2 JUnit-Tests verwenden 24 TestNG steht für „Test Next Generation“ analog der Fernsehserie Star Trek Next Generation. Ziel war es, frühzeitig die Annotation-Features von Java 1.5 (Tiger) zu nutzen und ein umfassenderes und besseres Testframework zu schreiben, als es die JUnit-3.*Familie bereitstellt. Entstanden ist ein Framework, das einige Aspekte mehr aufweist als JUnit 4 und vielleicht auch andere Projekte adressiert (siehe Vergleich am Ende des Buches). Cedric Beust startete TestNG 2003, da JUnit einige Mängel in Bezug auf Themen wie Gruppenbildung, Parametrisierbarkeit etc. aufwies und JUnit nicht besonders schnell auf Java Annotations reagierte. Ein Beispiel für den Mangel in JUnit sind die Methoden setUp() und tearDown(). Sie haben einen Klassenscope. Oftmals wünscht sich der Entwickler aber eine feinere (vor und nach jeder einzelnen Methode) oder gröbere Reichweite (vor jeder Testgruppe oder jeder Testsuite). Zudem sollte TestNG auch auf eine Integration mit Ant optimiert sein. Dies entspricht eher dem Zyklus der Continous Integration (Source-Repository, Test, Build, Deploy, Refactoring etc.). Ein Ablauf mittels Testrunner ist zwar schön, passt aber eher nicht in eine professionelle und buildgesteuerte Umgebung. In dieser er- schnell + kompakt 15 3 – TestNG – eine Einführung hält man dann mit TestNG viel umfassendere Reports, als dies mit den JUnit Testrunnern möglich ist. Aber es gibt auch Vereinfachungen: So kann man unter TestNG das Schlüsselwort assert für seine Tests nutzen oder beliebige Exceptions werfen, um den Test scheitern zu lassen. Mit logischen Operatoren oder Methoden kann bei der Nutzung von assert jede Methode aus org.testng.AssertJUnit.* nachgebildet werden. Wem dies nicht reicht, der importiert und nutzt einfach die Methoden aus JUnit oder aus anderen Frameworks wie JTiger. Profitipp Das wichtigste Feature unter TestNG ist aber sicherlich, sehr flexibel Testgruppen definieren zu können. Es empfiehlt sich daher, sich bereits während der Entwicklung der Tests unbedingt Kategorien zu überlegen und diese mit Tests zu füllen. 3.1 Schnellstart Ziel dieses Abschnitts ist es, schnell zu Ergebnissen zu kommen. Alle Beispiele wurden unter Eclipse codiert. Erst später schauen wir uns Plug-ins an, die alles noch weiter vereinfachen. Installation TestNG ist über http://testng.org zu erreichen. Der DownloadBereich enthält einige ältere Versionen, aber an oberster Stelle den letzten Build von TestNG. Heruntergeladen werden kann eine Zip-Datei (hier testng-5.1.zip). 16 Schnellstart Abb. 3.1: TestNG-Installationsverzeichnis Kurz eine Erklärung der Verzeichnisse: 쐌 3rdparty: Enthält externe Bibliotheken. (1) bsh-*.jar – enthält die BeanShell-Bibliothek (Java-Interpreter, der dynamisch Java und Skript-Elemente ausführen kann: beanshell.org). (2) qdox*.jar – enthält einen Parser, der aus Java-Dateien entsprechende Klassen/Interfaces oder Methoden zurückliefern kann: qdox.codehaus.org). (3) util-concurrent.jar ist eine Bibliothek ähnlich wie java.util.concurrent, mit Features für den verteilten Zugriff auf Hashmaps, Queues, Semaphoren etc. 쐌 doc: Das doc-Verzeichnis ist leider nur ein Abbild dessen, was auf dem Web unter testng.org/doc/documentation-main.html zu finden ist. 쐌 examples: Dieses Verzeichnis enthält eine Datei, in der die wichtigsten Tags (@Test, @Configuration) mit ihren Parametern aufgeführt sind. 쐌 javadocs: Hier ist die Javadoc-API zu finden. Dies sollte immer verwendet werden, um Parameter und deren Beschreibung nachzuschlagen. Zum Beispiel bietet die Annotation BeforeClass die Parameter alwaysRun, dependsOnGroups, dependsOnMethods, description, enabled, groups und inheritGroups. schnell + kompakt 17 3 – TestNG – eine Einführung 쐌 src: Enthält einen Teil der TestNG-Sources. Um TestNG selbst zu „builden“, sollten die aktuellen Quellen von http:// code.google.com/p/testng/ gezogen werden. 쐌 test & test-14: Enthält umfangreiche Ant-Buildskripte für Ant unter Java 1.4 und 5. Am wichtigsten sind jedoch die beiden TestNG Jars für Java 1.4 und Java 1.5. Wir verwenden letztere Bibliothek testng-5.1jdk15.jar. Testfile & Buildfile Wir starten hier einmal entgegen der TDD-Reihenfolge und erstellen die folgende triviale Klasse, die es zu testen gilt: package com.testngbook.ch01; public class Calc { public int add(int a, int b){ return a+b; } public int sub(int a, int b){ return a-b+1; // Fehler } } In dieser Trivialklasse möchten wir erst die Methode add und danach auch sub testen. Wie bereits erwähnt, arbeitet TestNG hier mit Ant (ant.apache.org) als „Testrunner“, das wir gleich einbinden werden. Als Nächstes benötigen wir die Testdatei: 18 Schnellstart package com.testngbook.ch01; import org.testng.annotations.*; public class CheckCalc { Calc c = new Calc(); @Test(groups = { "GroupStart" }) public void bTest() { assert c.add(4,5) == 9 : "Kommentar..."; } } Der erste Import wird benötigt, um das Testtag bekannt zu machen. Wird dieser vergessen, so ist @Test nicht bekannt. In dem Testtag weiter unten kommt eine Gruppe zum Einsatz, die später noch erklärt, aber gleich im Ant-Buildfile aufgerufen wird. Danach verwenden wir das normale Java-Assert. Später zeigen wir, wie man u.a. auch die JUnit-Asserts verwenden kann, falls man auf diese gerne zurückgreifen möchte. Hinweis Zur Erinnerung, TestNG stellt in der Klasse org.testng.AssertJUnit die JUnit-Testmethoden zur Verfügung. Man kann aber auch selbst Exceptions werfen, das Java-Schlüsselwort assert nehmen oder auf andere Methoden von Frameworks wie JTiger zurückgreifen. Interessant ist hierbei natürlich auch, dass die Testmethode keinen vorgeschriebenen Namen mehr haben muss. Hier heißt sie einfach bTest. schnell + kompakt 19