Junit Solutions Web Applications and Services. Standing on the shoulders of giants l Special thanks...
-
Upload
wilfrid-payne -
Category
Documents
-
view
217 -
download
2
Transcript of Junit Solutions Web Applications and Services. Standing on the shoulders of giants l Special thanks...
Standing on the shoulders of giants
Special thanks to:• Mike Clark
JUnit FAQ Maintainerwww.clarkware.com
• Glenn Vanderburg
Philosophy
“Any program feature without an automated test simply
doesn’t exist.”
from Extreme Programming Explained, Kent Beck
Analogy
“It's like trying to build a pyramid by starting at the top, rather than the bottom. No matter how hard you
try, you're doomed to failure.”
from http://www.counterpane.com/comprehensive.html
Testing pyramid
APIDeve
loper time
Delivered application Angry customers
Iteration builds Customer / developer re
work
Assertions
Software must and will change over time. Right? We desire clean uncluttered code. Right? Can we do both? If so, how?
Refactoring
Restructuring of software by applying a series of internal changes
that do not affect its observable behavior
Fowler, Refactoring, 1999
What is JUnit
De facto Java unit testing framework Integrated nicely with IDEs and Ant Easy to learn
Our first unit testpackage org.example.antbook.common;
import junit.framework.TestCase;
public class SearchUtilTest extends TestCase {
public void testSearch() throws Exception { // right API? Document[] docs = SearchUtil.findDocuments("erik");
assertTrue(docs.length > 0); }}
Lean and green
package org.example.antbook.common;
public class SearchUtil {
public static final Document[] findDocuments(String queryString) throws SearchQueryException, SystemException { Document[] results = new Document[1]; return results; }}
JUnit Assertions
assertTrue(boolean condition)assertFalse(boolean condition)
assertEquals(Object expected, Object actual)• Uses equals() comparison• Overloaded for all primitive types
assertSame(Object expected, Object actual)assertNotSame(Object expected, Object actual)
• Uses == comparison
assertEquals(float expected, float actual, float tolerance)
assertNull(Object o)assertNotNull(Object o)
fail(String message)
+ overloadedString methods
JUnit Design - Pattern dense
Assert
TestCase TestSuite
<<interface>>
Test
YourTest
*
Courtesy of Mike Clarkwww.clarkware.com
JUnit Rules and Conventions
Subclass TestCase Prior to v3.8, String-arg constructor required Test methods
• public void testXXX() [throws …]• Any number of assertions per method
Implement main to run from command-line, but not necessary
Optionally add setUp / tearDown methods.
Test fixturepackage org.example.antbook.ant.lucene;
import java.io.IOException;import junit.framework.TestCase;
public class HtmlDocumentTest extends DocumentTestCase{ HtmlDocument doc;
public void setUp() throws IOException { doc = new HtmlDocument(getFile("test.html")); }
public void testDoc() { assertEquals("Title", "Test Title", doc.getTitle()); assertEquals("Body", "This is some test", doc.getBodyText()); }
public void tearDown() { doc = null; }}
Test Suitespackage org.example.antbook;
import junit.framework.Test;import junit.framework.TestCase;import junit.framework.TestSuite;
import org.example.antbook.junit.SimpleTest;import org.example.antbook.ant.lucene.HtmlDocumentTest;
public class AllTests { static public Test suite() { TestSuite suite = new TestSuite(); suite.addTestSuite(SimpleTest.class); suite.addTestSuite(HtmlDocumentTest.class); return suite; }}
Demo
JUnit Best Practices
Separate production and test code But typically in the same packages Compile into separate trees, allowing deployment
without tests Don’t forget OO techniques, base classing Test-driven development
– Write failing test first– Write enough code to pass– Refactor– Run tests again– Repeat until software meets goal– Write new code only when test is failing
Base classing
Groups of tests share common needspackage org.example.antbook.ant.lucene;
import java.io.File;import java.io.IOException;import junit.framework.TestCase;
public abstract class DocumentTestCase extends TestCase{ protected File getFile(String filename) throws IOException { String fullname = this.getClass().getResource(filename).getFile();
File file = new File(fullname);
return file; }}
Ant and JUnit
Two great tastes that taste great together You’re building with Ant already, now test with it too! Facilitates continuous integration and testing Richer and more flexible reporting than otherwise
possible, including publishing and e-mailing Fail builds if tests fail
<junit> task
<target name="test-summary" depends="test-compile">
<junit printsummary="yes" haltonfailure="true"> <classpath refid="test.classpath"/> <test name="org….HtmlDocumentTest"/> </junit>
</target>
<batchtest> and formatters<target name="test-batch" depends="test-compile">
<junit printsummary="no" haltonfailure="true"> <classpath refid="test.classpath"/> <formatter type="brief" usefile="false"/> <formatter type="xml"/>
<batchtest todir="${test.data.dir}"> <fileset dir="${test.dir}” includes="**/*Test.class” /> </batchtest>
</junit>
</target>
Tricks of the trade<junit printsummary="no" errorProperty="test.failed" failureProperty="test.failed" fork="${junit.fork}">
<classpath refid="test.classpath"/>
<formatter type="brief" usefile="false"/> <formatter type="xml"/> <test name="${testcase}" todir="${test.data.dir}" if="testcase"/>
<batchtest todir="${test.data.dir}" unless="testcase"> <fileset dir="${test.dir}" includes="**/*Test.class"/> </batchtest>
</junit>
<fail message="Tests failed." if="test.failed"/>
<junitreport>
Aggregates XML generated by <junit> XML formatter output
Transforms result using XSLT into report Default “frames” and “noframes” HTML
stylesheets built-in, but customizable
<junitreport> syntax
<junitreport todir="${test.data.dir}">
<fileset dir="${test.data.dir}"> <include name="TEST-*.xml"/> </fileset>
<report format="frames” todir="${test.reports.dir}" />
</junitreport>
Ant Best Practices
Use naming conventions:• *Test.java• *TestCase.java
Fork <junit>, typically Use errorproperty and failureproperty Ironically, don’t failonerror Use <fail> after <junit> Use Ant properties for location of XML results and
reports <copy> resources to build directory Pass parameters using <sysproperty>
Passing parameters to tests<junit printsummary="no”…
<sysproperty key="docs.dir” file="${test.dir}” /> <sysproperty key="index.dir” file="${test.dir}/index” />…</junit>
private String docsDir = System.getProperty("docs.dir");private String indexDir = System.getProperty("index.dir");
Cactus
In-container unit testing Excellent for testing:
• EJB
• Servlets, Filters, Taglibs
• Container-dependent frameworks, like Struts
Cactus test casepackage org.example.antbook;import org.apache.cactus.ServletTestCase;import org.apache.cactus.WebRequest;public class RequestUtilTest extends ServletTestCase{ public void beginGetValueParam(WebRequest theRequest) { theRequest.setURL("localhost:8080", "/antbook", "/test/test.jsp", null, "param=url"); }
public void testGetValueParam() { request.setAttribute("param", "request"); assertEquals("url", RequestUtil.getValue(request, "param")); }
public void testGetValueAttribute() { request.setAttribute("param", "request"); assertEquals("request", RequestUtil.getValue(request, "param")); }}
Back to greenpackage org.example.antbook;
import javax.servlet.http.HttpServletRequest;
public class RequestUtil { public static final String getValue (HttpServletRequest request, String key) { String value = request.getParameter(key); if (value != null) { return value; } value = (String) request.getAttribute(key); if (value != null) { return value; }
return null; }}
Cactus details
<runservertests> task to start, test, stop Deploy
• Tests
• Cactus APIs
• Cactus-enabling web.xml
XDoclet diversion - conditional Cactus<webdoclet destdir="${build.dir}/web/WEB-INF" force="${xdoclet.force}" mergedir="metadata/web"> <fileset dir="src/web"/>
<configParam name="cactusOn” value="${enable.cactus}” /> <deploymentdescriptor validatexml="true" destdir="${build.dir}/${site}" />
</webdoclet>
XDoclet web.xml merge point
<XDtConfig:ifConfigParamEquals paramName="cactusOn” value="true">
<servlet> <servlet-name>ServletRedirector</servlet-name> <servlet-class> org.apache.cactus.server.ServletTestRedirector </servlet-class> </servlet> <servlet> <servlet-name>ServletTestRunner</servlet-name> <servlet-class> org.apache.cactus.server.runner.ServletTestRunner </servlet-class> </servlet>
</XDtConfig:ifConfigParamEquals>
StrutsTestCase
Runs as Mock or on Cactus Provides assertions for expected Struts
ActionErrors and forwards
StrutsTestCase Examplepackage org.example.antbook.struts;
import servletunit.struts.CactusStrutsTestCase;
public class SearchFormTest extends CactusStrutsTestCase { public SearchFormTest(String s) { super(s); }
public void testValidation() { addRequestParameter("query",""); setRequestPathInfo("/search"); actionPerform(); verifyActionErrors(new String[] {"query.required"}); verifyInputForward(); }
}
Cactus - Servlet Test Runner
New addition, allows tests to be run through browser
XML results returned Using XSLT capable browser, report transformed
to HTML on the fly
Other JUnit Extensions
HttpUnit• Parses HTML results into DOM• Easy link navigation and form population• Useful for automated acceptance tests
Canoo WebTest• HttpUnit inside Ant
JUnitPerf• Wrap any JUnit tests• Measure desired performance and scalability tolerances
Continuous Integration
Build often, triggered by commit even Anthill
• Maciej & Urbancode rock!
CruiseControl Gump
Unit testing issues
How do I test database dependent code?• dbUnit
Should I test my user interface? How?• HttpUnit• Canoo WebTest
But, before you test at these levels, see if refactoring is possible
Conclusions
“Any program feature without an automated test simply doesn’t exist”
Testable code improves confidence and design Easy! “Keep the bar green to keep the code clean!”
Online Resources
JUnit.org• http://www.junit.org
Cactus• http://jakarta.apache.org/cactus
Clover• http://www.thecortex.net/clover
dbUnit• http://www.dbunit.org
HttpUnit• http://www.httpunit.org
Canoo WebTest• http://webtest.canoo.com
Mike Clark’s site• http://www.clarkware.com
Glenn’s reference card• http://www.delphis.com/java/junit-refcard.pdf
Book Resources
eXtreme Programming Explained: Embrace Change & Test Driven Design• Kent Beck
Refactoring: Improving the Design of Existing Code• Martin Fowler (Addison-Wesley, 1999)
Java Tools for Extreme Programming• Rick Hightower and Nick Lesiecki (Wiley, 2001)
Last but not least…
Chapter 4: Testing with JUnit
Chapter 12: coverage of Cactus
Chapter 15: Testing web services
Test-centric throughout