Test infected: Web Testing mit HttpUnit und Cactus Framework Peter Roßbach (pr@webapp.de)
Agenda Web Komponenten Test Build Verification Anmerkungen JUnit HTTPUnit ServletUnit Cactus Build Verification cruisecontrol Anmerkungen
Motivation XP-Techniken für das Testen Kostengünstige Lösung für das Testen von Web-Anwendungen Automatisierung der Erzeugung Automatisierte Tests Protokollierung und Benachrichtigung der Tests Teamentwicklung fördern
JUNIT ANT *..* Tomcat
Testing Game Coding Planning Game Standards Programming Simple Design Short Releases Refactoring Testing Continuous Integration
Ziele Unit Test während der Entwicklung Funktionale Test für Web-Anwendungen Automatisierung der Erzeugnisse Versionisierung Protokollierung Lasttest
Effektiv Testen möglichst zeitnah zur Programmierung automatisiert und damit wiederholbar muss Spaß machen Testen so oft wie Kompilieren so einfach wie Kompilieren Fehler finden, nicht Fehlerfreiheit beweisen
TestArten Unit Tests White-Box Tests isolierter Einheiten Akzeptanztests Black-Box Tests funktionaler Anforderungen weitere Systemtests Lasttests Performanztests Usability-Tests ...
Junit Java-Framework zum Schreiben und Ausführen automatischer Unit Tests Tests werden in Java codiert. Entsprechende Frameworks sind für andere Programmiersprachen erhältlich. Autoren Kent Beck and Erich Gamma
Anforderung verfeinern JUNIT Testprozess Klasse Testcase Anforderung klären Rumpf anlegen Testcase schreiben Kompilieren Testcase ausführen Funktionalität implementieren Testcase scheitert Nächste Anforderung Testcase erfolgreich Anforderung verfeinern Refactoring
JUNIT PizzaBinderTest package de.objektpark.jspTutorial.model; import junit.framework.*; public class PizzaBinderTest extends TestCase { public PizzaBinderTest (String testName) { super(testName); } public static Test suite() { return new TestSuite(PizzaBinderTest.class); } protected void setUp() throws Exception { ... } protected void tearDown() throws Exception { ... } public void testBind() throws Exception { List objects = null; objects = retriever("pizza"); assert(" no pizza bind", objects.get(0) instanceof Pizza);
JUNIT SwingUi
JUNIT Testtipps Jeder Aspekt der Klasse sollte einem Test unterzogen werden: Randparameter Test Unzulässige Werte Schleifeninvarianten Sie können nur die Funktionsergebnisse testen: Returnwerte Zustand der Objekte
JUNIT Testtipps Schreiben Sie kleine Methoden in Ihren Klassen und in den TestCases. Schreiben Sie die Test i.d. Regel vor Implementierung oder nahezu zeitgleich. Keine gleichzeitige Verbesserung des Codes und Korrektur von Fehlern.
JUNIT Testtipps Trennung von Testvorgehen Bug Fixing Refactoring Re-Design Neue Funktionalitäten Testvorgehen Bottom Up Top Down
JUNIT Web-Testumgebung Jakarta Ant 1.4.1 Intellij IDEA 2.5 Jakarta Tomcat 4.0.4 od 4.1.0 James 2.0.2 HttpUnit Cactus CruiseControl
Agenda Testing J2EE Testanforderung HttpUnit SerlvetUnit Cactus
J2EE Application Server J2EE Umgebung Client Applikations Logik EIS JDBC Web Container RDMS (X)HTML / XML Java Mail Servlets JSPs TagLibs Mail Server J2EE Application Server Java APIs RMI Java Applet Java App EJB Container IIOP Corba (Java) Application JNDI Session Beans MessageDriven Beans Entity Beans DS JMS Java APIs Message Queue
J2EE Test Anforderung Trennung von Kommunikation und Funktionalität Testbarkeit der Komponenten im Entwurf berücksichtigen Verwendung des erprobten JUNIT-Framework Test von Java Klassen ohne Server Deployment Test von Servlet/JSP oder EJB, die auf dem Server ablaufen
J2EE Test Vorgehen Funktionaler Unit Test Code + Logik Unit Test HttpUnit Code + Logik Unit Test Mock Objekte ServletUnit Integration Unit Test Cactus
HTTPUnit HTTPUnit basiert auf JUNIT HTTPUnit nutzt JTidy zum HTML Parsing und Xerces für XML Remote Test für HTTP Server OpenSource Lizenz Autor ist Russel Gold Aktuelle Version ist 1.3 Unterstützung Servlet API >=2.0
HTTPUnit Eigenschaften Cookie Support HTTP Authentification SSL Support Response HTML als Objekte XML als DOM Test für alle Klassen Eigener Pseudo Web Server Servlet Emulation
HTTPUnit Architektur Web Server Testclient Servlet Container JSP Cgi-bin Junit TestRunner HttpUnit TestCase HttpUnit Web- Conversation Ressourcen
HTTPUnit Klassen WebConversation Web-Browser Emulation, Cookie Management, Relative Url, Request/Response Ausführen / HTTP u. HTTPS GetMethodWebRequest HTTP GET Request PostMethodWebRequest HTTP POST Request WebResponse Ergebnis eines Requests WebLink HTML Link im WebResponse WebForm HTML Form im WebResponse SubmitButton FROM Submit Buttons WebTable HTML Table im WebResponse TableCell HTML Table Cell WebFrame HTML Frameset im WebResponse HttpUnitOptions Globale Options
HTTPUnit Login Seite
HTTPUnit JSP_indexTest public class JSP_indexTest extends Testcase { ... public void testLogin() throws Exception { WebConversation wc = new WebConversation(); WebResponse resp = wc.getResponse(getHostPath()); WebLink link = resp.getLinkWith("Anmelden"); resp = wc.getResponse(link.getRequest()); assertIncludeForm(resp, 1); WebForm form = resp.getForms()[0] ; assertLoginForm(form); assertLoginCustomer(wc, form.getRequest(),"3"); }
HTTPUnit JSP_indexTest private void assertIncludeForm( WebResponse aResponse, int expectedforms) throws Exception { WebForm[] forms = aResponse.getForms(); if (expectedforms > 0) { assertNotNull("login with no fields", forms); int length = forms.length; assert("Expected " + expectedforms, expectedforms == length); } else { assert("No forms expected", null != forms); }
HTTPUnit JSP_indexTest private void assertLoginForm(WebForm form) throws Exception { String[] parameterNames = form.getParameterNames(); int length = parameterNames.length; assert("Number of parameters wrong -- was <" + length + "> expected <10>", 9 == length); assertEquals("First parameter doAction", "doAction", parameterNames[0]); assertEquals("First parameter id", "id", parameterNames[1]); assertEquals("First parameter firstname", "firstname", parameterNames[2]); assertEquals("First parameter lastname", "lastname", parameterNames[3]); ... }
HTTPUnit JSP_indexTest private void assertLoginCustomer( WebConversation wc, WebRequest req, String id) throws Exception { req.setParameter("id", id); WebResponse resp = wc.getResponse(req); assertIncludeForm(resp, 1); assertNotNull( (resp.getForms()[0]).getSubmitButton("next")); }
IDEA Integration Junit Editor Ant
HTTPUnit Demo Start JBuilder oder IDEA Start Tomcat mit jspTutorial Start Junit Testcase Bewertung des Ergebnisses Inside Code Änderung der Testcases
HTTPUnit Anmerkungen Blackbox Test Seitenablaufplan als Basis der Testfalldefinition Kontrolle des Design Kontrolle der Links Kontrolle zwischen Entwickler und Designer XML und HTML Ausgabe testbar Unabhängigkeit von Server Technologie (ASP,JSP,PHP)
Cactus 1.2 Neues Jakarta Projekt aus der J2EEUnit entstanden Container Side Testing Testcases haben Client und Remote Bestandteil Deployment der Testcases auf dem Server Autor ist Vincent Massol
Cactus Eigenschaften Test Prüfung auf dem Client und dem Server Testen von Situationen, die nur auf dem Server existieren Support von Servlet API 2.2 und 2.3 Getestet mit Tomcat 3.2.x, 3.3 4.x; Resin 1.2,1.3 ; Weblogic 5.1, 6.x Umfangreiche Testcases und gute Dokumentation
Cactus Architektur Web Server Testclient Servlet Container Junit TestRunner Cactus TestCase Cactus Redirector Proxy Cactus TestCase Server seitige Testklassen
Cactus ServletTestCase Implizite Attribute der ServletTestCase Klasse Attribute Klasse config javax.servlet.ServletConfig session javax.servlet.http.HttpSession response javax.servlet.http.HttpServletResponse request javax.servlet.http.HttpServletRequest
Cactus Servlet Example I public void testReadServletOutputStream() throws IOException { SampleServlet servlet = new SampleServlet(); servlet.doGet(request, response); } public void endReadServletOutputStream (HttpURLConnection theConnection) throws IOException assertEquals("<html><head/><body>A GET request</body></html>", AssertUtils.getResponseAsString(theConnection));
Cactus Servlet Example II public void beginSendParams(ServletTestRequest theRequest) { theRequest.addParameter("param1", "value1"); theRequest.addParameter("param2", "value2"); } public void testSendParams() SampleServlet servlet = new SampleServlet(); Hashtable params = servlet.getRequestParameters(request); assert(params.get("param1") != null); assert(params.get("param2") != null); assertEquals("value1", params.get("param1")); assertEquals("value2", params.get("param2"));
Cactus Servlet Example III public void beginXXX(WebRequest theRequest) { theRequest.setURL("jakarta.apache.org", "/mywebapp", "/test/test.jsp", null, null); theRequest.addCookie("cookiename", "cookievalue"); } public void testXXX() { MyServletToTest servlet = new MyServletToTest(); servlet.init(config); servlet.methodToTest(); // Servlet methods assertEquals("someValue", session.getAttribute("someAttribute")); assertEquals("jakarta.apache.org", request.getServerName()); } public void endXXX(WebResponse theResponse) { cookie = theResponse.getCookie("cookiename"); assertEquals("cookievalue", cookie.getValue()); assertEquals("some content here", theResponse.getText());
Cactus JspTestCase Implizite Attribute der JspTestCase Klasse config javax.servlet.ServletConfig session javax.servlet.http HttpSession response javax.servlet.http HttpServletResponse request javax.servlet.http.HttpServletRequest out javax.servlet.jsp.JspWriter pageContext org.apache.cactus.server.PageContextWarpper
Cactus JSP Example I public class ForwardTest extends JspTestCase {... public void testForward() throws ServletException,IOException { pageContext.forward("/test/test.jsp") ; } public void endForward(HttpURLConnection theConnection) throws IOException { StringBuffer sb = new StringBuffer(); BufferedReader input = new BufferedReader( new InputStreamReader(theConnection.getInputStream())); while (null != ((String str = input.readLine()))) { sb.append(str); input.close (); assertEquals( "<html><body>Hello !</body></html>", sb.toString());
Cactus JSP Example II public class ForwardTest extends JspTestCase {... public void testForward() throws ServletException,IOException { pageContext.forward("/test/test.jsp") ; } public void endForward(WebResponse theResponse) { assertEquals( "<html><body>Hello !</body></html>", theResponse.getText() );
Cactus EJB Example a public class ConverterTest extends ServletTestCase { ... private Converter converter ; public void setUp() throws Exception { Context ctx = new InitialContext(); ConverterHome home = (ConverterHome) PortableRemoteObject.narrow( ctx.lookup("java:comp/ejb/Converter"),ConverterHome.class); this.converter = home.create(); }
Cactus EJB Example b public class ConverterTest extends ServletTestCase { ... public void testConvert() throws Exception { assertNotNull("Can‘t access Converter", converter) ; double dollar = this.converter.convertYenToDollar(100.0); assertEquals("dollar", 1.0, dollar, 0.01); } public void tearDown() throws Exception { if( converter != null) this.converter.remove() ;
Cactus EJB Example c <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/j2ee/dtds/web-app_2.2.dtd"> <web-app> <servlet> <servlet-name>ServletRedirector</servlet-name> <servlet-class>org.apache.cactus.server.ServletTestRedirector</servlet-class> </servlet> <servlet-mapping> <servlet-name>ServletRedirector</servlet-name> <url-pattern>/ServletRedirector/</url-pattern> </servlet-mapping> [...] <ejb-ref> <ejb-ref-name>ejb/Converter</ejb-ref-name> <ejb-ref-type>Session</ejb-ref-type> <home>org.apache.cactus.sample.ejb.ConverterHome</home> <remote>org.apache.cactus.sample.ejb.Converter</remote> </ejb-ref> </web-app>
Cactus Demo Test, ob Session und ServletContext korrekt gestartet sind Pizza und Ingredient testen TagLib Test im “Build Verification“-Abschnitt
Cactus Anmerkungen White Box Test Unterstützung vieler Servlet Container Remote Testing via HTTP Test von Client und Server Zustände Pro Testfall zwei HTTP Verbindungen ( response, result) Testbarkeit aller J2EE Komponenten Version 1.3 verfügbar
Agenda Integration Build Verfication Ant CruiseControl
Build Verfication Tägliche Integration der Änderung Automatisches Erzeugen via ant build Prepare Compile Packaging Deploy Test Release
Build Verification Test Continuous Integration Martin Fowler Matthew Foemmel Self Testing Code Complete Automatic Test Single Source Master Build Cruisecontrol 1.2.1a
BVT Architektur CruiseControl Ant build resource src web Project checking CVS files checkout Web Client Test Web Container buildservlet masterbuild cruisecontrol Build timer test deploy produce Mail Client Java Mail Logfiles protocol JMX Admin
BVT CruiseControl
BVT JMX Admin
BVT Demo Starten der Dienste Einbringen einer Änderung Beobachten des Integrationslaufs Benachrichtigung Anschauen der Protokolle Administration
BVT Ergebnisse I Verantwortung des Teams wächst Hohe Sicherheit der Stabilität der Änderung Anzahl der TestCases wächst stärker vor Releases Nicht der gesamte Code muss getestet werden Testfälle und Abdeckung müssen beobachtet werden -> Review der Testfälle
BVT Ergebnisse II Zeitplan muss Testfall- Anpassungen bei ReDesign berücksichtigen Zeitersparnisse der Integrationstest vs. Pflege der Testfälle Review der Kodierung der Testfälle Konventionen und Pattern suchen
Tipps und Tricks I Aufteilen der Erzeugnisse eines Projektes Suche nach hilfreichen ant tasks Cactus,Quick,Jtidy,Junit, jspc Erweiterung des xsl-Skript durch Links auf die Erweiterungen Integration sollte auf Produktionsplattform ablaufen Schnelle Reaktionen
Tipps und Tricks II Test von verschiedenen Server mit Cactus JSP Compiler (Tomcat JSPC) zum Syntax Check Automatische Installation eines Releases Markieren eines Erfolgreichen Builds mit CURRENT Tag Integration von Statistiken Anzahl Klassen vs Testklassen Anzahl erfolgreicher Builds
Tipps und Tricks III Durchführung des Tests Build JSPC Test Java Beans Test Deployment Validierung der Deployment Descriptoren Start der Server Serverseitige Testfälle Sicherung der Ergebnisse
Tipps und Tricks IV Gesamtes Team bekommt CruiseControl Status Email Verantwortlichen für die Stabilität des Integrationstest bennenen Besetzung der Rolle Deployers Grenze zwischen Qualitätssicherung und Entwicklertest vereinbaren Wartung der TestCase einplanen
Noch nicht genug! Mailto: pr@webapp.de „Play with the Tools!“ http://www.tom4.de Lassen Sie sich von mir beraten.
Testtools CruiseControl http://cruisecontrol.sourceforge.net/ JMeter http://java.apache.org/jmeter/ Watchdog http://jakarta.apache.org/watchdog/ JUnit http://www.junit.org/ Cactus http://jakarta.apache.org/commons/cactus/index.html JUnitX http://www.exterme-java.de/ JTest http://www.parasoft.com/products/jtest/index.htm http://www.javaworld.com/jw-03-2001/jw-0323-lw-jtest.html QACenter http://www.compuware.com/products/qacenter/ Jbuilder Opentools http://www.borland.com/ Ant http://jakarta.apache.org/ant/ Rational Test Suite http://www.rational.com/
Test Veröffentlichungen Junit Primer http://www.clarkware.com/articles/JUnitPrimer.html Test Infect EJB http://www.javaworld.com/javaworld/jw-05-2000/jw-0526-testinfect.html HttpUnit http://httpunit.sourceforge.net/ Servlet Testing http://www.delphis.com/javacon2000/servlet.html Junitservlet http://sourceforge.net/projects/junitservlet J2EEUnit http://sourceforge.net/projects/j2eeunit/ JUnitPerf http://www.clarkware.com/software/JUnitPerf.html JUnit best practices http://www.javaworld.com/javaworld/jw-12-2000/jw-1221-junit_p.html Continuous Integration http://www.martinfowler.com/articles/continuousIntegration.html Junit.org Articles http://www.junit.org/articles.htm
Test-Bücher Hightower/Lesiecki (Wiley 2001) Java Tools for eXtreme Programming http://www.rickhightower.com/JavaXPToolkit/ Newkrik/Martin (Addsion Weseley 2001) Extreme Programming in Practice Splaine/Jaskiel (STQE Publishing 2001 The Web Testing Handbook Link (dpunkt verlag 2002) Unit Tests mit Java
JSP-Bücher Fields/Kolb (Manning 2000) Web Development with Java Server Pages Kassem et al. (Addison Wesley 2000) Designing Enterprise Applications with the Java 2 Plattform, Enterprise Edition (APM-Book) Pekowsky ( Addison Wesley 2000) JavaServer Pages Turau (IX- dpunkt 2000) Java Server Pages -Dynamische Generierung von Web-Dokumenten Avedal et al. (Wrox 2000) Professional JSP Bergsten ( O‘Reilly 2000) JavaServerPages Rossbach/Schreiber (1999,2000) Java Server und Servlets
Links Sun JSP Home Page http://java.sun.com/jsp/ OReilly JSP Book http://www.TheJspBook.com/ Jakarta(Tomcat, Ant, Taglib...) http://jakarta.apache.org/ Jsp Tutorial http://www.ix.heise.de/ix/artikel/2000/07/152/ http://www.ix.heise.de/ix/artikel/2000/08/148/ http://www.ix.heise.de/ix/artikel/2000/09/172/ Manning Book http:/jspTags.com/ Jason Hunter Site http://www.servlets.com/ JawaWorld http://www.javaworld.com/ Bea http://www.bea.com/ Orion http://www.orionserver.com/ Jrun Allaire http://www.alliare.com/jrun/ WebApp Framework http://www.webapp.de/