Object Mentor Blog: Testing GUIs Part II: JSP http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp en-us 40 Testing GUIs Part II: JSP <p>How do you test JSPs <em>outside</em> the container, with no web server running&#8230;</p> <h1 style="text-align:center;">Testing <span class="caps">JSP</span> pages.</h1> <p>One of the more annoying aspects of working on a web application is that you have to deploy it in order to test it. This doesn&#8217;t apply to everything of course; if you are careful with your design you can test the business rules in plain old java objects. You can test database access, interface layers, and stored procedures without the web server running. But testing the <span class="caps">GUI</span> &#8211; the <span class="caps">HTML</span> produced from the <span class="caps">JSP</span> files &#8211; is very hard to do unless the system has been deployed.</p> <p>Lot&#8217;s of teams fall back on Selenium, Mercury, or other tools that test GUIs <em>through</em> the web server. However, this leads to very fragile tests that break when the <em>format</em> of a page changes, even though it&#8217;s content remains unchanged. Other teams solve the fragility problem by using Cactus, or the somewhat more primitive tools in <code>HtmlUnit</code> and <code>HttpUnit</code>, to inspect the generated <span class="caps">HTML</span> delivered to them by the running web application. We&#8217;ll talk about those techniques in another blog in this series.</p> <p>In this article I will demonstrate a simple technique for testing <span class="caps">JSP</span> pages using <code>JUnit</code> and <code>HtmlUnit</code>, <em>completely outside</em> the container. The advantages of such a technique should be clear.</p> <ul> <li>You don&#8217;t have to have the container running, or even working. You can test your JSPs before you have even chosen a particular webserver. </li> <li>You can spin around the edit/compile/test loop much more quickly because you don&#8217;t have to redeploy after every edit.</li> <li>You can build your JSPs incrementally using Test Driven Development to guide their construction.</li> </ul> <p>The reason that testing JSPs outside the container isn&#8217;t more common is because JSPs are <em>designed</em> to run inside the container. The designers never gave a lot of thought to running them outside the container. So the code generated by the <span class="caps">JSP</span> compiler depends on facilities supplied by the container. Even the tools that generate the <span class="caps">JSP</span> code expect that you already have a webapp that can be deployed. Therefore, in order to run outside the container, you somehow have to fake these facilities and tools.</p> <h3 style="color:blue;text-align:center;">Dependency Management Rant.</h3> <div style="background:lightgrey;color:blue;margin-left:1cm;margin-right:1cm;font-family:times;font-size:150%">Why do so many designers of frameworks and tools expect you to live within their narrow world view? Why must I have a fully functional web app before I can <em>compile</em> my JSPs? Why must they run within the container? Information hiding has been one of the foundational tenets of good software design for decades. When will our industry begin to take it seriously?</div> <h3>Compiling JSPs</h3> <p>The first step to testing JSPs is to compile them into servlets. To do that, we first have to translate them from <span class="caps">JSP</span> format to <span class="caps">JAVA</span>. The <em>apache</em> project provides a tool named <em>Jasper</em> that does this. Invoking <em>Jasper</em> on a <span class="caps">JSP</span> named <code>MyPage.jsp</code> creates a <span class="caps">JAVA</span> source file named <code>MyPage_jsp.java</code>. This file can then be compiled into a servlet using your favorite <span class="caps">IDE</span>. (Mine is IntelliJ).</p> <p>Unfortunately <em>Jasper</em> was not designed to be run from the command line. Or rather, half of it was, and half of it wasn&#8217;t. <em>Jasper</em> does in fact have a main function that takes standard command line arguments. And it is <em>feasible</em> to issue the command <code>java org.apache.jasper.JspC</code> to invoke it. However, <em>Jasper</em> expects the environment it runs in to be consistent with the environment of the container. It expects many the <em>apache</em> JAR files to be in the <span class="caps">CLASSPATH</span>. It also expects to see a <code>web.xml</code> file that describes the web application, and it wants to see a <span class="caps">WEB</span>-INF directory with all the appropriate web application <span class="caps">JAR</span> files and <span class="caps">TLD</span> files present. In short, <em>Jasper</em> expects there to be a webapp.</p> <p>To make matters worse, there appear to be bugs in the version of <em>Jasper</em> that I am using (tomcat 5.5.20) that cause it to generate slightly incorrect code unless it is invoked in a manner that is consistent with the way that <span class="caps">TOMCAT</span> invokes it.</p> The first issue is inconvenient but is just a matter of creating the appropriate directories and files and then invoking <em>Jaser</em> from <span class="caps">ANT</span> so that the classpaths are easy to control. The second issue required a fair bit of research and experimentation to get working right. But in the end, the following ant file seems to work quite nicely. Look at the last task to see the <code>JspC</code> invocation. <pre><code> &lt;project name="Library" default="compile" basedir="."&gt; &lt;property environment="env"/&gt; &lt;property name="build.home" value="${basedir}/build"/&gt; &lt;property name="build.war.home" value="${build.home}/war"/&gt; &lt;property name="build.classes.home" value="${build.home}/classes"/&gt; &lt;property name="build.jar.home" value="${build.home}/jars"/&gt; &lt;property name="catalina.home" value="${env.CATALINA_HOME}"/&gt; &lt;property name="dist.home" value="${basedir}/dist"/&gt; &lt;property name="web.home" value="${basedir}/web"/&gt; &lt;path id="compile.classpath"&gt; &lt;fileset dir="lib"&gt; &lt;include name="*.jar"/&gt; &lt;/fileset&gt; &lt;pathelement location="${catalina.home}/common/classes"/&gt; &lt;fileset dir="${catalina.home}/common/endorsed"&gt; &lt;include name="*.jar"/&gt; &lt;/fileset&gt; &lt;fileset dir="${catalina.home}/common/lib"&gt; &lt;include name="*.jar"/&gt; &lt;/fileset&gt; &lt;pathelement location="${catalina.home}/shared/classes"/&gt; &lt;fileset dir="${catalina.home}/shared/lib"&gt; &lt;include name="*.jar"/&gt; &lt;/fileset&gt; &lt;/path&gt; &lt;target name="clean"&gt; &lt;delete dir="${build.home}"/&gt; &lt;delete dir="${dist.home}"/&gt; &lt;/target&gt; &lt;target name="compile"&gt; &lt;mkdir dir="${build.classes.home}"/&gt; &lt;javac srcdir="${src.home}" destdir="${build.classes.home}" excludes="**/*Test.java"&gt; &lt;classpath refid="compile.classpath"/&gt; &lt;/javac&gt; &lt;/target&gt; &lt;target name="jar" depends="compile"&gt; &lt;mkdir dir="${build.jar.home}"/&gt; &lt;jar jarfile="${build.jar.home}/application.jar" basedir="${build.classes.home}" includes="**/application/**/*.class" /&gt; &lt;/target&gt; &lt;target name="dist" depends="jar"&gt; &lt;copy todir="${build.war.home}"&gt; &lt;fileset dir="${web.home}"/&gt; &lt;/copy&gt; &lt;copy todir="${build.war.home}/WEB-INF/lib"&gt; &lt;fileset dir="${build.jar.home}" includes="*.jar"/&gt; &lt;/copy&gt; &lt;mkdir dir="${dist.home}"/&gt; &lt;jar jarfile="${dist.home}/${app.name}.war" basedir="${build.war.home}"/&gt; &lt;/target&gt; &lt;target name="jsp" depends="dist"&gt; &lt;delete dir="${basedir}/testjsp"/&gt; &lt;java classname="org.apache.jasper.JspC" fork="true"&gt; &lt;arg line="-v -d ${basedir}/testjsp -p com.objectmentor.library.jsp -mapped -compile -webapp ${build.war.home}"/&gt; &lt;arg line="WEB-INF/pages/patrons/books/loanRecords.jsp"/&gt; &lt;classpath&gt; &lt;fileset dir="${catalina.home}/common/lib"&gt; &lt;include name="*.jar"/&gt; &lt;/fileset&gt; &lt;fileset dir="${catalina.home}/server/lib"&gt; &lt;include name="*.jar"/&gt; &lt;/fileset&gt; &lt;fileset dir="${catalina.home}/bin"&gt; &lt;include name="*.jar"/&gt; &lt;/fileset&gt; &lt;fileset dir="${build.war.home}/WEB-INF/lib"&gt; &lt;include name="*.jar"/&gt; &lt;/fileset&gt; &lt;pathelement location="/Developer/Java/Ant/lib/ant.jar"/&gt; &lt;/classpath&gt; &lt;/java&gt; &lt;jar jarfile="${build.jar.home}/jsp.jar" basedir="${basedir}/testjsp" includes="**/jsp/**/*.class" /&gt; &lt;/target&gt; &lt;/project&gt;</code></pre> <p>Of course you need all the standard files and directories beneath <code>${build.war.home}</code> to make this work. If you are using custom tags in your JSPs, make sure you have all the appropriate <span class="caps">TLD</span> files in your <code>tld</code> directory.</p> <p>Notice that the <span class="caps">ANT</span> file invokes the JspC command line, rather than using the JspC ant task that comes with <span class="caps">TOMCAT</span>. All the docs will tell you to use that ant task. However, I found that it doesn&#8217;t work well when you have custom tags. Maybe I&#8217;m just dumb, or maybe there is a bug in <em>Jasper</em>; but the only way I found to get <em>Jasper</em> to generate the right code was to invoke it from the command line <em>and explicitly pass the <span class="caps">JSP</span> files in as command line argument!</em>. If you depend on either the ant task or the command line to scan the whole web app for all the <span class="caps">JSP</span> files, it seems to generate the wrong code. (See: <a href="http://blog.objectmentor.com/articles/2007/02/08/jasper-problem-resolved">this blog</a>)</p> <p>Now that we have a <span class="caps">JAVA</span> file, let&#8217;s take a look at it. First, here&#8217;s the <span class="caps">JSP</span> file.</p> <pre><code>&lt;%@ page import="com.objectmentor.library.utils.DateUtil" %&gt; &lt;%@ page import="com.objectmentor.library.web.controller.patrons.LoanRecord" %&gt; &lt;%@ page import="java.util.List" %&gt; &lt;% List loanRecords = (List) request.getAttribute("loanRecords"); if (loanRecords.size() &gt; 0) { %&gt; &lt;table class="list" id="loanRecords"&gt; &lt;tr&gt; &lt;th&gt;ID&lt;/th&gt; &lt;th&gt;Title&lt;/th&gt; &lt;th&gt;Due date&lt;/th&gt; &lt;th&gt;Fine&lt;/th&gt; &lt;/tr&gt; &lt;% for (int i = 0; i &lt; loanRecords.size(); i++) { LoanRecord loanRecord = (LoanRecord) loanRecords.get(i); %&gt; &lt;tr class="&lt;%=i%2==0?"even":"odd"%&gt;"&gt; &lt;td&gt;&lt;%=loanRecord.id%&gt; &lt;/td&gt; &lt;td&gt;&lt;%=loanRecord.title%&gt; &lt;/td&gt; &lt;td&gt;&lt;%=DateUtil.dateToString(loanRecord.dueDate)%&gt; &lt;/td&gt; &lt;td&gt;&lt;%=loanRecord.fine.toString()%&gt; &lt;/td&gt; &lt;/tr&gt; &lt;% } %&gt; &lt;/table&gt; &lt;% } %&gt;</code></pre> <p>And here is the code that <em>Jasper</em> created from this file.</p> <pre><code>package com.objectmentor.library.jsp.WEB_002dINF.pages.patrons.books; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; import com.objectmentor.library.utils.DateUtil; import com.objectmentor.library.web.controller.patrons.LoanRecord; import java.util.List; public final class loanRecords_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent { private static java.util.List _jspx_dependants; public Object getDependants() { return _jspx_dependants; } public void _jspService(HttpServletRequest request, HttpServletResponse response) throws java.io.IOException, ServletException { JspFactory _jspxFactory = null; PageContext pageContext = null; HttpSession session = null; ServletContext application = null; ServletConfig config = null; JspWriter out = null; Object page = this; JspWriter _jspx_out = null; PageContext _jspx_page_context = null; try { _jspxFactory = JspFactory.getDefaultFactory(); response.setContentType("text/html"); pageContext = _jspxFactory.getPageContext(this, request, response, null, true, 8192, true); _jspx_page_context = pageContext; application = pageContext.getServletContext(); config = pageContext.getServletConfig(); session = pageContext.getSession(); out = pageContext.getOut(); _jspx_out = out; out.write('\n'); out.write('\n'); out.write('\n'); List loanRecords = (List) request.getAttribute("loanRecords"); if (loanRecords.size() &gt; 0) { out.write("\n"); out.write("&lt;table class=\"list\" id=\"loanRecords\"&gt;\n"); out.write(" &lt;tr&gt;\n"); out.write(" &lt;th&gt;ID&lt;/th&gt;\n"); out.write(" &lt;th&gt;Title&lt;/th&gt;\n"); out.write(" &lt;th&gt;Due date&lt;/th&gt;\n"); out.write(" &lt;th&gt;Fine&lt;/th&gt;\n"); out.write(" &lt;/tr&gt;\n"); out.write(" "); for (int i = 0; i &lt; loanRecords.size(); i++) { LoanRecord loanRecord = (LoanRecord) loanRecords.get(i); out.write("\n"); out.write(" &lt;tr class=\""); out.print(i%2==0?"even":"odd"); out.write("\"&gt;\n"); out.write(" &lt;td&gt;"); out.print(loanRecord.id); out.write("\n"); out.write(" &lt;/td&gt;\n"); out.write(" &lt;td&gt;"); out.print(loanRecord.title); out.write("\n"); out.write(" &lt;/td&gt;\n"); out.write(" &lt;td&gt;"); out.print(DateUtil.dateToString(loanRecord.dueDate)); out.write("\n"); out.write(" &lt;/td&gt;\n"); out.write(" &lt;td&gt;"); out.print(loanRecord.fine.toString()); out.write("\n"); out.write(" &lt;/td&gt;\n"); out.write(" &lt;/tr&gt;\n"); out.write(" "); } out.write("\n"); out.write("&lt;/table&gt;\n"); } } catch (Throwable t) { if (!(t instanceof SkipPageException)){ out = _jspx_out; if (out != null &#38;&#38; out.getBufferSize() != 0) out.clearBuffer(); if (_jspx_page_context != null) _jspx_page_context.handlePageException(t); } } finally { if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context); } } } </code></pre> <h3 style="color:blue;text-align:center;">Rant About Final.</h3> <div style="background:lightgrey;color:blue;margin-left:1cm;margin-right:1cm;font-family:times;font-size:150%">Why is this class declared <code>final</code>? What if I had wanted to derive from it to create a testing stub? Why would <em>anyone</em> think that generated code is so sacrosanct that I wouldn&#8217;t want to override it.</div> <p><br/> A quick perusal of this code tells us that in order to use an instance of this servlet we need an <code>HttpServletRequest</code> instance, and an <code>HttpServletResponse</code> instance.</p> <p>Looking a little closer we find that the servlet writes all the <span class="caps">HTML</span> to an instance of <code>JspWriter</code> that it gets from something called a <code>PageContext</code>. So, if we could create a mocked up version of <code>JspWriter</code> that saves all this <span class="caps">HTML</span>, and a mocked up version of <code>PageContext</code> that delivers the mocked <code>JspWriter</code>, then we could access the written <span class="caps">HTML</span> from our tests.</p> <p>Fortunately the <span class="caps">TOMCAT</span> designers decoupled the creation of the <code>JspWriter</code> into a factory named <code>JspFactory</code>. That factory can be overridden! This means that we can get our mocked up <code>JspWriter</code> into the servlet without modifying the servlet. All we need is something like the following code:</p> <pre><code> class MockJspFactory extends JspFactory { public PageContext getPageContext(Servlet servlet, ServletRequest servletRequest, ServletResponse servletResponse, String string, boolean b, int i, boolean b1) { return new MockPageContext(new MockJspWriter()); } public void releasePageContext(PageContext pageContext) { } public JspEngineInfo getEngineInfo() { return null; } }</code></pre> <p>Now we need the mocked <code>JspWriter</code>. For the purposes of this demonstration, I used the following:</p> <h3 style="font-family:courier;text-align:center;">MockJspWriter</h3> <pre><code>package com.objectmentor.library.web.framework.mocks; import javax.servlet.jsp.JspWriter; import java.io.IOException; public class MockJspWriter extends JspWriter { private StringBuffer submittedContent; public MockJspWriter(int bufferSize, boolean autoFlush) { super(bufferSize, autoFlush); submittedContent = new StringBuffer(); } public String getContent() { return submittedContent.toString(); } public void print(String arg0) throws IOException { submittedContent.append(arg0); } public void write(char[] arg0, int arg1, int arg2) throws IOException { for (int i=0; i&lt;arg2; i++) submittedContent.append(String.valueOf(arg0[arg1++])); } public void write(String content) throws IOException { submittedContent.append(content); } // lots of uninteresting methods elided. I just gave them // degenerate implementations. (e.g. {}) } </code></pre> <p>Don&#8217;t be concerned about the comment regarding all the unimplemented methods I elided. I&#8217;ve taken the attitude that I will only implement those methods that I need to get my tests to work. The others I leave with degenerate implementations.</p> <p>My <span class="caps">IDE</span> was very helpful in creating these mocks. It automatically builds method prototypes and degenerate implementations for all the methods of an interface or abstract class that need implementing.</p> <p>The <code>MockPageContext</code>, <code>MockHttpServletRequest</code> and <code>MockHttServletResponse</code> classes were created in a similar way.</p> <h3 style="font-family:courier;text-align:center;">MockPageContext</h3> <pre><code>package com.objectmentor.library.web.framework.mocks; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; import java.io.IOException; import java.util.Enumeration; public class MockPageContext extends PageContext { private final JspWriter out; private HttpServletRequest request; public MockPageContext(JspWriter out) { this.out = out; request = new MockHttpServletRequest(); } public JspWriter getOut() { return out; } public ServletRequest getRequest() { return request; } // lots of degenerate functions elided. } </code></pre> <h3 style="font-family:courier;text-align:center;">MockHttpServletRequest</h3> <pre><code>package com.objectmentor.library.web.framework.mocks; import javax.servlet.*; import javax.servlet.http.*; import java.io.*; import java.security.Principal; import java.util.*; public class MockHttpServletRequest implements HttpServletRequest { private String method; private String contextPath; private String requestURI; private HttpSession session = new MockHttpSession(); private Map parameters = new HashMap(); private Map attributes = new HashMap(); public MockHttpServletRequest(String method, String contextPath, String requestURI) { super(); this.method = method; this.contextPath = contextPath; this.requestURI = requestURI; } public MockHttpServletRequest() { this("GET"); } public MockHttpServletRequest(String method) { this(method, "/Library", "/Library/foo/bar.jsp"); } public String getContextPath() { return contextPath; } public String getMethod() { return method; } public String getRequestURI() { return requestURI; } public String getServletPath() { return requestURI.substring(getContextPath().length()); } public HttpSession getSession() { return session; } public HttpSession getSession(boolean arg0) { return session; } public Object getAttribute(String arg0) { return attributes.get(arg0); } public String getParameter(String arg0) { return (String) parameters.get(arg0); } public Map getParameterMap() { return parameters; } public Enumeration getParameterNames() { return null; } public void setSession(HttpSession session) { this.session = session; } public void setParameter(String s, String s1) { parameters.put(s, s1); } public void setAttribute(String name, Object value) { attributes.put(name, value); } // Lots of degenerate methods elided. } </code></pre> <h3 style="font-family:courier;text-align:center;">MockHttpServletResponse</h3> <pre><code>package com.objectmentor.library.web.framework.mocks; import javax.servlet.ServletOutputStream; import javax.servlet.http.*; import java.io.*; import java.util.Locale; public class MockHttpServletResponse implements HttpServletResponse { // all functions are implemented to be degenerate. } </code></pre> <p>Given these mock objects, I can now create an instance of my <code>loanRecords_jsp</code> servlet and start calling methods on it! Indeed, my first test case looked something like this:</p> <pre><code> public void testSimpleTest() throws Exception { MockJspWriter jspWriter = new MockJspWriter(); MockPageContext pageContext = new MockPageContext(jspWriter); JspFactory.setDefaultFactory(new MockJspFactory(pageContext)); HttpJspBase jspPage = new loanRecords_jsp(); HttpServletRequest request = new MockHttpServletRequest(); HttpServletResponse response = new MockHttpServletResponse(); jspPage._jspInit(); jspPage._jspService(request, response); assertEquals("", jspWriter.getContent()); }</code></pre> <p>The test fails, as expected, because the content is a bit more than blank &#8211; but not much more. If you look carefully at the <span class="caps">JSP</span> file you&#8217;ll see that it calls <code>request.getAttribute("loanRecords")</code> and expects a List back. But since our test did not create such an attribute, the code throws an exception that is silently caught.</p> <p>To get real <span class="caps">HTML</span> out of this servlet, we need to load up the attributes. Then we can use HtmlUnit to parse that <span class="caps">HTML</span> and write tests against it.</p> <p>HtmlUnit is very simple to use, especially for testing generated web pages like this. There are a few gotcha&#8217;s that I described <a href="http://blog.objectmentor.com/articles/2007/02/11/dependency-management-httpunit">here</a></p> <p>Here is the final test that loads the attributes, inspects the <span class="caps">HTML</span> with htmlUnit, and passes appropriately:</p> <pre><code>package com.objectmentor.library.jspTest.books.patrons.books; import com.gargoylesoftware.htmlunit.*; import com.gargoylesoftware.htmlunit.html.*; import com.objectmentor.library.jsp.WEB_002dINF.pages.patrons.books.loanRecords_jsp; import com.objectmentor.library.utils.*; import com.objectmentor.library.web.controller.patrons.LoanRecord; import com.objectmentor.library.web.framework.mocks.*; import junit.framework.TestCase; import org.apache.jasper.runtime.HttpJspBase; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; import java.util.*; public class LoanRecordsJspTest extends TestCase { private MockPageContext pageContext; private MockJspWriter jspWriter; private JspFactory mockFactory; private MockHttpServletResponse response; private MockHttpServletRequest request; private WebClient webClient; private TopLevelWindow dummyWindow; protected void setUp() throws Exception { jspWriter = new MockJspWriter(); pageContext = new MockPageContext(jspWriter); mockFactory = new MockJspFactory(pageContext); JspFactory.setDefaultFactory(mockFactory); response = new MockHttpServletResponse(); request = new MockHttpServletRequest(); webClient = new WebClient(); webClient.setJavaScriptEnabled(false); dummyWindow = new TopLevelWindow("", webClient); } public void testLoanRecordsPageGeneratesAppropriateTableRows() throws Exception { HttpJspBase jspPage = new loanRecords_jsp(); jspPage._jspInit(); List&lt;LoanRecord&gt; loanRecords = new ArrayList&lt;LoanRecord&gt;(); addLoanRecord(loanRecords, "99", "Empire", DateUtil.dateFromString("2/11/2007"), new Money(4200)); addLoanRecord(loanRecords, "98", "Orbitsville", DateUtil.dateFromString("2/12/2007"), new Money(5200)); request.setAttribute("loanRecords", loanRecords); jspPage._jspService(request, response); StringWebResponse stringWebResponse = new StringWebResponse(jspWriter.getContent()); HtmlPage page = HTMLParser.parse(stringWebResponse, dummyWindow); HtmlElement html = page.getDocumentElement(); HtmlTable table = (HtmlTable) html.getHtmlElementById("loanRecords"); List&lt;HtmlTableRow&gt; rows = table.getHtmlElementsByTagName("tr"); assertEquals(3, rows.size()); assertEquals("even", classOfElement(rows.get(1))); assertEquals("odd", classOfElement(rows.get(2))); List&lt;HtmlTableDataCell&gt; firstRowCells = rows.get(1).getCells(); assertEquals(4, firstRowCells.size()); List&lt;HtmlTableDataCell&gt; secondRowCells = rows.get(2).getCells(); assertEquals(4, secondRowCells.size()); assertLoanRecordRowEquals("99", "Empire", "02/11/2007", "$42.00", firstRowCells); assertLoanRecordRowEquals("98", "Orbitsville", "02/12/2007", "$52.00", secondRowCells); } private String classOfElement(HtmlTableRow firstDataRow) {return firstDataRow.getAttributeValue("class");} private void assertLoanRecordRowEquals(String id, String title, String dueDate, String fine, List&lt;HtmlTableDataCell&gt; rowCells) { assertEquals(id, rowCells.get(0).asText()); assertEquals(title, rowCells.get(1).asText()); assertEquals(dueDate, rowCells.get(2).asText()); assertEquals(fine, rowCells.get(3).asText()); } private void addLoanRecord(List&lt;LoanRecord&gt; loanRecords, String id, String title, Date dueDate, Money fine) { LoanRecord loanRecord = new LoanRecord(); loanRecord.id = id; loanRecord.title = title; loanRecord.dueDate = dueDate; loanRecord.fine = fine; loanRecords.add(loanRecord); } private class MockJspFactory extends JspFactory { private PageContext pageContext; public MockJspFactory(PageContext pageContext) { this.pageContext = pageContext; } public PageContext getPageContext(Servlet servlet, ServletRequest servletRequest, ServletResponse servletResponse, String string, boolean b, int i, boolean b1) { return pageContext; } public void releasePageContext(PageContext pageContext) { } public JspEngineInfo getEngineInfo() { return null; } } } </code></pre> <p>This test makes sure that the generated <span class="caps">HTML</span> has the appropriate content contained within the rows of a table. The test <em>does</em> expect to see a table, and expects the rows to appear in the appropriate order. It also ensures that the rows will have alternating styles. Other than that, all issues of form and syntax are ignored.</p> <h3>Conclusion</h3> <p>The technique described here can be used to test virtually any static web page, or portion thereof <em>outside</em> of a container, and without a webserver running. It is relatively simple to set up; and then very easy to extend. With it, you can spin around the edit/compile/test loop very quickly, and can easily follow the rules of Test Driven Development.</p> Sun, 11 Feb 2007 20:54:37 -0600 urn:uuid:be6396f8-d544-4aab-9520-8bc8a5ff3eeb Uncle Bob http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp Uncle Bob's Blatherings Testing GUIs http://blog.objectmentor.com/articles/trackback/162 "Testing GUIs Part II: JSP" by specialized cycling jersey Now the fabric of several common comparative performance as follows:<a href="http://www.cyclingjersey2012.com/team-clothing-specialized-c-2_68.html" rel="nofollow">specialized cycling jersey</a> warmth retention property can:specialized cycling jersey thick hair riding under thin catch caught under thick hair riding bike mesh thin mesh riding take take note: in the season alternate period thin catch hair and thick mesh riding bike under the boundaries of service and is not so obvious, according to their own needs in. <p>The permeability: thick catch hair riding under thin catch hair riding under thick mesh take ride bike under elastic thin mesh performance: <a href="http://www.cyclingjersey2012.com/team-clothing-sportful-c-2_126.html" rel="nofollow">sportful cycling jersey</a>thick catch hair riding under thin catch hair riding under thick mesh take pin thin mesh riding under speed dry performance: thick catch hair riding underthin catch hair riding under thick mesh take pin thin mesh riding clothing.pants pad for &quot;Coolmax&quot; three-dimensional cutting molding silicone pad, accord with human body to the latest classical design,<a href="http://www.cyclingjersey2012.com/team-clothing-subarutrek-c-2_90.html" rel="nofollow">subaru-trek cycling jersey</a> by seven different density of silicon gel complex such as soil cooling insert,</p> <p> provide senior protection,<a href="http://www.cyclingjersey2012.com/team-clothing-sportful-c-2_126.html" rel="nofollow">Tour De Francecycling jersey</a> has four layers of stretch way, capital cost is high. Perspiration breathable fully adhere to skin and not displacement, the permanent the bacteria and microbe treatment, long after the movement also won&#8217;t produce from his sweaty; Edge line soft, minimize the friction, long time but will not collapse, make you ride more dry and comfortable.</p> Sun, 20 May 2012 21:51:21 -0500 urn:uuid:24d14ab5-42e2-447d-8081-928cd751b6df http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-225562 "Testing GUIs Part II: JSP" by sadf <p><a href="www.baidu.com" rel="nofollow">baidu</a></p> Sun, 20 May 2012 21:49:38 -0500 urn:uuid:564897b2-24ed-4b95-892a-7f05911bcea6 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-225561 "Testing GUIs Part II: JSP" by Injection mold <p>Intertech Machinery Inc. provides the most precise Plastic Injection Mold and Rubber Molds from Taiwan. With applying excellent unscrewing device in molds,</p> <p>Intertech is also very professional for making flip top Cap Molds in the world. Mold making is the core business of Intertech (Taiwan). With world level technology, Intertech enjoys a very good reputation for making Injection Mold and Plastic Molds for their worldwide customers.</p> Fri, 18 May 2012 01:41:38 -0500 urn:uuid:cbf22c1e-8cdd-49d2-b3f4-d39e7870073a http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-225172 "Testing GUIs Part II: JSP" by Team Jersey Clothing <p> With the development of the social and economic, we spend more, but enjoy less. We should realize that life is a chain of moments of enjoyment, not only about survival. Spend more time with your family and friends, eat your favorite foods, visit the places you love. Do not delay anything that adds laughter and joy to your life. Put on <a href="http://www.montonsale.com/" rel="nofollow">Cycling Shorts</a> and riding a bicycle to go outdoor enjoying yourselves right now.</p> Thu, 17 May 2012 21:57:51 -0500 urn:uuid:8d2e05fb-e449-44be-8dc3-b7d4564c98fc http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-225155 "Testing GUIs Part II: JSP" by Montonsale <p>Wearing the <a href="http://www.montonsale.com/team-jersey-lotto-c-1_19.html" rel="nofollow">Team Jersey Clothing</a> and cycling on the road, you can keep stepping on so that you arrive at the destination. Flying your feelings, releasing yourself. You don&#8217;t keep anything for a special occasion, because every day that you live is a special occasion</p> Thu, 17 May 2012 21:41:28 -0500 urn:uuid:eda87f45-a4f4-483a-99eb-ad303e19a99f http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-225153 "Testing GUIs Part II: JSP" by bicycjersy <p>many people choose riding as sport?<a href="http://www.cyclingjersey.biz/" rel="nofollow">Cycling Jersey</a> Fast responders gain fitness quickly because, for some unknown reason, their cells are capable of changing rapidly. Others take much longer, perhaps years, to realize the same gains. The problem for slow responders is that they often give up before reaping the benefits of training. Figure 1.1 illustrates the response curve.Other beginners may eventually catch up to and surpass the most successful novices. This is often due to the different rates at which the human body responds to training.</p> Thu, 17 May 2012 03:18:09 -0500 urn:uuid:f4a762d5-5d1a-4fe6-8b0c-aa2db6eceb1e http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-225004 "Testing GUIs Part II: JSP" by Montonsale <p><a href="http://www.montonsale.com/cycling-equipment-cycling-gloves-c-1_55_63_67_70.html" rel="nofollow">Cycling Golves</a> The riding gloves are divided into half and full finger. When you are purchasing, please choose which the stitching part is sturdy and the part of palm is thick. Some gloves whose thumb plus towel material to easily wipe sweat for the rider.<br> The full fingers&#8217; gloves are very important equipment for riders of cycling in the winter <a href="http://www.montonsale.com/cycling-equipment-cycling-gloves-c-1_55_63_67_70.html" rel="nofollow">Bike Accessories</a>.</p> Sat, 12 May 2012 21:28:46 -0500 urn:uuid:d3eaa506-8cdf-45a6-a891-8d54b5cedde1 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-223979 "Testing GUIs Part II: JSP" by bicycjersy <p>Sleep to win the headphones to avoid <a href="http://www.monstersbeatsshop.us/" rel="nofollow">beats studio outlet</a> ruining the headphones, headphones unit is Pazang to the part of <a href="http://www.monstersbeatsshop.us/beats-by-dre-studio-c-2.html" rel="nofollow">Studio Beats By Dr Dre</a> nets has become the focus of protection, first of all to ensure clean,do not let the unit part of the excessive exposure to dust. 2 line of headphones is more delicate, so should be avoided in the course of the pull, stress and other man-made damage.Three new headphones bought as much as possible do not immediately CS game.<a href="http://www.monstersbeatsshop.us/beats-by-dre-tour-c-4.html" rel="nofollow">Beats By Dre Tour</a> CS sound for the diaphragm is still relatively tight new headphones stimulate the still relatively large. Soothing music so you should use the appropriate &quot;praise&quot;, and let it slowly into the state after normal use.</p> Sat, 12 May 2012 03:42:56 -0500 urn:uuid:4313e287-1468-4adc-a685-4e700326d695 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-223925 "Testing GUIs Part II: JSP" by HTC Cycle Jersey <p>The end of the 2011 Tour de France match Aldi when the 12th stage from the flexor Mourinho to Lvzi &#8211; This is the current Tour de France mountain stages. Samuel, the fleet of Spain, 11 &#8211; Sanchez 6 hours 1 minute 15 seconds of stage wins, this is his personal stage wins for the first time, Sanchez won the road race <a href="http://www.cycleequip.com/team-jersey-htc-c-1_16.html" rel="nofollow">HTC Cycle Jersey</a>champion in the 2008 Beijing Olympic Games. Vehicle fleet in Europe French driver Woke Le 9 6 hours, 2 minutes and 05 seconds, 51 hours 54 minutes 44 seconds to continue topping the list in the overall ranking list. Defending champion Kang Tade 8 to 6 hours, 1 minute 58 seconds, 51 hours 58 minutes 44 seconds results in the overall ranking list jumped into the top ten ranked 7 Small Shrek to the stage 6, a total score up the fourth, the advantages of Kangta De expanded to 1 minute 43 seconds. Italian champion Paso to fifth.<br> Today the game a total length of 211 km mountain stage is also the start of the first truly. 141.5 km at one a climbing point, 1538 meters above sea level, rising 9900 m section of the slope of 7.5%. 175.5 kilometers is a huge difficulty HC climbing points, altitude of 2115 meters, up 17.1 km section of 7.3%, slope second HC climbing points at the finish line, 1715 meters above sea level, rising sections of 1310 m, slope of 7.4 %. Competition in the local time 11:19 (17:19 GMT), a total of 176 players played. Up on a six-collar riding squad, where the team of 11 people several times collar rider Moreno to YDStaR team Gutierrez and gaming team, Roy, as well as the AG2R team the Ka Deli, Sky team of Thomas,, and fleet Man Geer. They quickly opened a gap between the large forces, have four minutes time advantage in the 20 km to 110 km, even gap widening to about 8 minutes and 3 seconds.<br> A goal to fight in the game, is 119 kilometers on the way sprint points, Man Geer beat Roy got. The next game is really the climax of competition: a climbing point and HC climbing points! Large forces rapidly to <a href="http://www.cycleequip.com/team-jersey-cannondale-c-1_27.html" rel="nofollow">Cannondale Cycle Jersey</a> narrow the distance, and the first six people and some sprint expert, such as Cavendish at this time are out of the most competitive group. Not far from a climbing point to leave that on the way at 141.5 km sprint points, a small group but also as leading to complete this point the conquest, but also Man Geer, he got the first breath revenue 10 Gradeability points. Large forces to leave them a distance of about 6 minutes.<br> A fast downhill is the most difficult since the start of the period of the current Tour de France uplink distance: 175.5 km at the HC level climbing points. During this journey before and after the distance between the squad of six completely disrupted the back of a large force is also touch on pieces by the Astana team Ke Luze and Joan bank fleet Dam force added to the leading teams, some rush, Roy got the first, which means to him to get 20 climbing points. To look at the large forces, the recent wave of riders and the distance between them has narrowed to about 3 minutes and 10 seconds.<br> Leave the end of 25 km at this time, began the last journey of the HC, two strongmen began to force most of the team, one 11 team Sanchez, another lottery team Fanneidete, it is fast two took the leading teams rushed mess, breath and red in the third and <a href="http://www.cycleequip.com/team-jersey-nalini-c-1_47.html" rel="nofollow">Nalini Cycle Jersey</a>fourth almost equal to Thomas and Roy, leaving the end of 10 km, the time gap between them is only 55 seconds! Next in succession Thomas and Roy can not hold, and quickly left behind Sanchez and Fanneidete, become the new leader! Behind most of the team&#8217;s most powerful group of people, Woke Le in the &quot;Yellow Force&quot; has been completed the previous teams that support the &quot;full coverage&quot;, leave the end of five kilometers, they with about 70 seconds behind Sanz and Fanneidete position.<br> The final game but calm, only the yellow jersey troops Shrek kill out, no one popped challenge the first two master, and then the distance, the large Shrek can not be a magical go-ahead, looking for the most in front of two fight. Samuel &#8211; Sanchez get stage wins, won his first title on the stage of the Tour de France! This is a somewhat unexpected result, as he won in the Beijing Olympic Games men&#8217;s road race accident<br> Celtics compete placid, Cavendish continues to 260 points in the first, climbing spots on sweater easy to master, today the end of the second HC-level climbing end point, the champion Sanchez with 40 points put on a climb slope spots shirt, new white shirt, French gaming team, Nathan, 52 hours, 0 minutes, 34 seconds at the total score of 13, put on a new white shirt. French AG2R team to 155 hours and 11 minutes and 39 seconds column in the team first. Sky team of Thomas dare bucket Award.The time trial is the fist project of Evans in the Tour de France really established the advantage! Group time trial, his driven, team overall speed also won the third high-ranking individuals, the stage 20 individual time trial, Evans finished second breath to win the biggest competition opponents Shrek brothers more than two and a half of the 19 stages that seems pretty huge disadvantage, all wiped out!<br> This is what sort of an all-powerful Evans, the fact that William Hill&#8217;s odds have been optimistic about Evans, but he is not most concerned about the vision of the fans of a certain level in the grass is always greener. Once upon a time, Evans A strong age Ulrich, fall short of a synonym, in 2007 and 2008 Tour de France is a classic two reason why the classic, all-cause the results between the champion and runner-up close Bainianhuanfa can into the top ten. Kangta De winning the first Tour de France champion in 2007, Evans, just 23 seconds and his gap! History can be <a href="http://www.cycleequip.com/team-jersey-trek-c-1_32.html" rel="nofollow">Trek Cycle Jerse</a> discharged into the championship gap minimum. Kangta De retirement match in 2008, the veteran Sastre win, Evans again &quot;only&quot; a gap of 58 seconds, can be discharged into the history of nine. People think that Evans will finish with a regrettable last career, his most brilliant handwriting respond: he still has the infinite power, to complete the first professional cyclist to overcome the self, beyond self-classic battle!<br> We do not have to estimate whether Evans winning a Tour de France champion, for the 34-year-old, he worked a lifetime goal finally achieved, even if it is to achieve a return, an individual&#8217;s career has also been perfect, 2011 7 February 24, in Paris, under a clear sky, Kader &#8211; Evans is the world&#8217;s unique pastoral pavilion Elysees Avenue, the King!</p> Fri, 11 May 2012 05:04:27 -0500 urn:uuid:aaa9954a-7664-4642-9276-b60f232f1c8e http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-223775 "Testing GUIs Part II: JSP" by evans cycles <p>This is bike Accessories indeed a bad day, <a href="http://www.bikejersysale.com" rel="nofollow">evans cycles</a> but not the worst, Kangta De Perhaps the first stage it was decided he can not carry the title of the ultimate fate, but why he ultimately received only 5? The reason for this is the 18th stage, a Kangta De play to the stage of complete failure. He received only 15 stages, completely lost the fight for the championship or even the first three ideas. <a href="http://www.bikejersysale.com" rel="nofollow">bicycle clothes</a> The reason is not he on the way for <a href="http://www.bikejersysale.com/bike-accessories-c-57.html" rel="nofollow">biking Accessories</a> Cycling Jerseys Team a new car, but a sudden in the last minute sprint summit due to <a href="http://www.bikejersysale.com/cycling-jerseys-team-castelli-c-1_25.html" rel="nofollow">Castelli bike Jersey</a>the poor state of backwardness, slaike finally admit biking jerseys to defending hopeless, but frankly exhaustion. You want to take in the Tour de France championship, climbing, and timing, the two most distanced themselves from the competition, a station can not neglect the results of the ground accidentally lose a mountain there&#8217;s a lost state, to get the final <a href="http://www.bikejersysale.com" rel="nofollow">cycle clothing</a> Section 5 The only table Mingkangtade at least in the other 19 stages to play very well.</p> Fri, 11 May 2012 05:00:41 -0500 urn:uuid:02273d58-6be2-427c-9bd6-fb322c079dfd http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-223774 "Testing GUIs Part II: JSP" by bicycjersy <p>Every year,<a href="http://www.bicycjersysale.com/team-jersey-lampre-c-1_23.html" rel="nofollow">Lampre Team Jersey</a> thousands of amateur athletes with the same exercise intensity training exercise organ desire to continue to transform the training stimulus to develop it <a href="http://www.bicycjersysale.com/team-jersey-c-1.html" rel="nofollow">cycling clothing</a>. The exercise intensity of long-term to <a href="http://www.bicycjersysale.com/team-jersey-ag2r-c-1_3.html" rel="nofollow">Quick-Step Team Jersey</a> maintain the same causes the body to become dinner, athletic performance will remain flat.</p> Thu, 10 May 2012 21:51:28 -0500 urn:uuid:3bd18cd2-5c48-46ab-bc76-4cb27ffc24a5 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-223632 "Testing GUIs Part II: JSP" by cyclingjerseys <p>Want to achieve fitness purposes by cycling friends, preferably with some professional protective <a href="http://www.cyclingjersey.biz/" rel="nofollow">Cycling Jersey</a> equipment, such as dice helmet, gloves, shoes and so on <a href="http://www.cyclingjersey.biz/team-jersey-astana-c-1_52.html" rel="nofollow">Astana cycling jerseys</a> . The dice helmet in high speed riding on dice Ministry has played an important role in the protection of and attention to wear when not exposed to the amount of dice; gloves to prevent slipping and <a href="http://www.cyclingjersey.biz/team-jersey-liquigas-c-1_8.html" rel="nofollow">Liquigas cycling jersey</a> scratches; sports shoes, the end of the sponge Diego a long time will soles acid swelling, and professional bike shoes is hard bottom, so that the pedaling power of all concentrated in the foot on.</p> Thu, 10 May 2012 21:49:21 -0500 urn:uuid:f761580f-c6fc-408d-a339-1800b2efe88c http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-223631 "Testing GUIs Part II: JSP" by bikeclothingsale@hotmail.com <p>Most of the rider is riding on the road day in the sun, the effect of the road <a href="http://www.bike-clothing.com/team-clothing-katusha-c-8_17.html" rel="nofollow">Katusha Cycling jersey</a> on the reflection of the sun better than the mud or grass. If <a href="http://www.bike-clothing.com/team-clothing-astana-c-8_54.html" rel="nofollow">Astana cycling jersey</a> eliminate their individual abilities and boil the remainder down to the most basic elements,The special role of the riding glasses in addition to shared role with general sports eyewear, <a href="http://www.bike-clothing.com/team-clothing-lotto-c-8_12.html" rel="nofollow">Lotto cycling jersey</a> and its blocking role of ultraviolet radiation is worth special attention. what is left are the attributes that bring success to the champions.</p> Sat, 05 May 2012 04:04:25 -0500 urn:uuid:0d434ef2-8ffa-4191-8fe5-601a9d99a436 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-222076 "Testing GUIs Part II: JSP" by Beats Pro Detox <p>Beats Dre Studio Red <a href="http://www.monstersbeatsshop.com/beats-dre-studio-white-p-16.html" rel="nofollow">Beats Studio White</a> have great sound,it doesnt happen without great cable.Advanced Quadripole 4 twisted pair construction reduces signal loss for perfectly balanced sound and extreme clarity.Beats Studio Red features highly advanced materials and construction to deliver a new level of audio accuracy and clarity.<a href="http://www.monstersbeatsshop.com/beats-dre-pro-detox-p-11.html" rel="nofollow">Beats Pro Detox</a> Beats Dre Studio delivers an unprecedented combination of super deep bass, smooth undistorted highs and crystal clear vocals never heard before from headphones.Less Noise, More Music With Powered Isolation,Extreme Comfort is Music to Your Ears,With Beats, you feel <a href="http://www.monstersbeatsshop.com/" rel="nofollow">Beats Studio</a> the music, not the headphones.All these Beats By Dr Dre Studio on our online store sell in low price. What&#8217;s more, The headphone can be delivered to your door freely.</p> Fri, 04 May 2012 01:44:56 -0500 urn:uuid:d89488cf-80e1-4ad5-9921-89e625aed270 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-221857 "Testing GUIs Part II: JSP" by bicycle jersey sale <p>The bike race is the fierce Bianchi <a href="http://www.cycleequip.com/team-jersey-htc-c-1_16.html" rel="nofollow">HTC Cycle Jersey</a> Cycle Jerse competition of the athletes speed, endurance and skills is also a competition of high-tech cycling equipment. Riding obey style to determine the color with carefully consider the selection and development of functional fabrics is the key to the design. From a professional point of view, the jersey is broadly divided into underwear riding, road riding clothes and riding coats into three categories. Types can be divided into: men jersey, women jersey Castelli Cycle Jersey and riding accessories and riding accessories can also be divided <a href="http://www.cycleequip.com/team-jersey-cannondale-c-1_27.html" rel="nofollow">Cannondale Cycle Jersey</a> into riding gloves, riding sleeves, riding hat, riding shoes, riding coat.<br> Demanding riding underwear personal wearing comfort of the fabric. The colder weather is usually used warm, breathable, thermal insulation, good polyester fabric; hotter weather, perspiration, breathable, washable and quick drying, lightweight fabric as the preferred, such as mesh polyester fabric. Many companies now Cannondale Cycle Jersey again sterilization, deodorization as the focus of the study. The ODLO riding <a href="http://www.cycleequip.com/team-jersey-castelli-c-1_25.html" rel="nofollow">Castelli Cycle Jersey</a> underwear company, in 2004 launched a deodorant fiber called effect of silver ions in the polyester fibers is not seen with the naked eye, can be effective in reducing bacterial growth in the underwear.</p> Fri, 04 May 2012 01:44:09 -0500 urn:uuid:521afacf-1bc5-471a-83dd-3b06c9cc9f29 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-221856 "Testing GUIs Part II: JSP" by shorts specialized <p>2008 Tour de <a href="http://www.bikejersysale.com/2010-saxo-bank-blue-and-red-cycling-jersey-bib-shortsjpg-p-1069.html" rel="nofollow">2010 Saxo Bank Blue And Red Cycling Jersey Bib Shorts</a> France is a classic two reason why the classic, all-cause the results between the champion and runner-up close Bainianhuanfa can into the top ten. Kangta De winning the first Tour de France champion in 2007, Evans, just 23 seconds and his gap! History can be <a href="http://www.bikejersysale.com/cycling-jerseys-team-raleigh-c-1_43.html" rel="nofollow">BMC bike Jersey</a> discharged into the championship gap minimum. Kangta De retirement match in 2008, the veteran Sastre win, Evans again &quot;only&quot; a gap of 58 seconds, can be discharged into the history of nine. People think that Evans will finish with a regrettable last career, his most <a href="http://www.bikejersysale.com/2011-scott-cycling-jersey-and-shorts-kits-yellowjpg-p-662.html" rel="nofollow">2011 Scott Cycling Jersey And Shorts Kits Yellow</a> brilliant handwriting respond: he still has the infinite power, to complete the first professional cyclist to overcome the self, beyond self-classic battle!</p> Fri, 04 May 2012 01:42:39 -0500 urn:uuid:78afc3a0-97a4-4ecd-9a4a-7f58642a5422 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-221854 "Testing GUIs Part II: JSP" by Beats Pro Detox <p>Beats Dre Studio Red <a href="http://www.monstersbeatsshop.com/beats-dre-studio-white-p-16.html" rel="nofollow">Beats Studio White</a> have great sound,it doesnt happen without great cable.Advanced Quadripole 4 twisted pair construction reduces signal loss for perfectly balanced sound and extreme clarity.Beats Studio Red features highly advanced materials and construction to deliver a new level of audio accuracy and clarity.<a href="http://www.monstersbeatsshop.com/beats-dre-pro-detox-p-11.html" rel="nofollow">Beats Pro Detox</a> Beats Dre Studio delivers an unprecedented combination of super deep bass, smooth undistorted highs and crystal clear vocals never heard before from headphones.Less Noise, More Music With Powered Isolation,Extreme Comfort is Music to Your Ears,With Beats, you feel <a href="http://www.monstersbeatsshop.com/" rel="nofollow">Beats Studio</a> the music, not the headphones.All these Beats By Dr Dre Studio on our online store sell in low price. What&#8217;s more, The headphone can be delivered to your door freely.</p> Fri, 04 May 2012 01:41:57 -0500 urn:uuid:a3ef7176-da96-4fc3-afa9-0852a06494a9 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-221853 "Testing GUIs Part II: JSP" by mulberry bags <p>Like another groups of <a href="http://www.mulberrybag.co/mulberry-bayswater-bags-c-5.html" rel="nofollow">Mulberry Bayswater Bag</a> skill using the Hmong. numerous Hmong culture, pure elements collected. The standard lifestyle and manufacturing work, close friendsand family members celebrations, religious move, then, for instance textiles, embroideries, feeding, wedding, worship and so forth here. <a href="http://www.mulberrybag.co/mulberry-bayswater-bags-c-5.html" rel="nofollow">Mulberry bayswater bags</a> These social factors in to the architectural type belonging to the immediate surface. Or implied during the type of inside construction. mainly because of those methods andorganic conditions, then the long-term consequences of those social factors type the architectural functions belonging to the contents belonging to theHmong. Hmong females possess <a href="http://www.mulberrybag.co/mulberry-holdall-bags-c-6.html" rel="nofollow">Mulberry Holdall Bags</a>the upper entire body is getting in basic and narrow sleeves, collar, jacket, pleated pants. Capable of reaching total apparel or long, stylish scene, not knee-length or short, graceful and touching.</p> <p>&nbsp;</p> Fri, 04 May 2012 01:41:20 -0500 urn:uuid:2827a690-767d-4ec9-9c91-d79285e942ea http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-221852 "Testing GUIs Part II: JSP" by Australian golfing holidays <p>Your article is extremely impressive. I never considered that it was feasible to accomplish something like that until after I looked over your post . Please visit our website for more information .</p> Tue, 01 May 2012 12:28:15 -0500 urn:uuid:382360e5-8efd-4e8c-abac-f5fb8a259cf1 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-221069 "Testing GUIs Part II: JSP" by louboutin sales <p>Testing GUIs Part II: JSP 114 hoo,good article!!I like the post!11</p> Fri, 20 Apr 2012 18:46:23 -0500 urn:uuid:e4d57279-2a63-4c8a-ab2c-8dbd713f0a74 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-218976 "Testing GUIs Part II: JSP" by jackofgammon@gmail.com <p>Really i appreciate the effort you made to share the knowledge. The topic here i found was really effective to the topic which i was researching for a long time <a href="http://www.dckeyslocksmith.com/" rel="nofollow">dc locksmith</a></p> Fri, 30 Mar 2012 16:17:15 -0500 urn:uuid:64895698-a8c7-4f7c-b3d6-0e95d9e9454a http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-213973 "Testing GUIs Part II: JSP" by youngbrown <p>Thanks for the information, I&#8217;ll visit the site again to get update information <a href="http://www.indiaplaza.com/" rel="nofollow">online shopping</a></p> Tue, 27 Mar 2012 03:56:49 -0500 urn:uuid:ca0c30de-9205-4148-bc1f-1d28df0d6afa http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-213310 "Testing GUIs Part II: JSP" by Outlook Repair <p>An insightful blog&#8230; JSP is not a Java GUI&#8230; it&#8217;s an HTML GUI generated by Java.. By contrast, this list is about testing GUIs implemented in Java, e.g. using AWT/Swing or SWT.. <a href="http://www.outlookrepairhelp.com/" rel="nofollow">Outlook Repair</a></p> Thu, 08 Mar 2012 06:25:41 -0600 urn:uuid:b4447c9f-72a7-4ae3-85cd-7d56742e1148 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-209039 "Testing GUIs Part II: JSP" by soccer jerseys <p><a href="http://www.2012jerseyssale.com/" rel="nofollow"><strong>soccer jerseys</strong></a> is very popular. Recently my friend and I always play them.</p> Sun, 04 Mar 2012 23:56:01 -0600 urn:uuid:47f140a8-55b3-4043-a97e-067e26e60829 http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-207916 "Testing GUIs Part II: JSP" by purple supras <p>Supra shoes have a lot of color, purple supras is one of most popular, you will like it!</p> Sun, 04 Mar 2012 20:44:17 -0600 urn:uuid:a385916b-4c12-4f37-bafa-45436a77d16f http://blog.objectmentor.com/articles/2007/02/11/testing-guis-part-ii-jsp#comment-207871