From: Steve F. <sm...@us...> - 2002-09-02 22:40:14
|
Update of /cvsroot/mockobjects/no-stone-unturned/doc/xdocs In directory usw-pr-cvs1:/tmp/cvs-serv3673/doc/xdocs Modified Files: a_longer_example.xml Log Message: first working servlet test, no answers found Index: a_longer_example.xml =================================================================== RCS file: /cvsroot/mockobjects/no-stone-unturned/doc/xdocs/a_longer_example.xml,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- a_longer_example.xml 27 Aug 2002 19:17:33 -0000 1.3 +++ a_longer_example.xml 2 Sep 2002 22:40:11 -0000 1.4 @@ -114,7 +114,7 @@ <programlisting> HttpServletRequest mockRequest = new NullHttpServletRequest() { public String getMethod() { - return "PUT"; + return "GET"; } public String getProtocol() { return "HTTP/1.1"; @@ -157,11 +157,178 @@ As you've seen in the first example, now we only have to override the methods that we use in our test. </para> </sidebar> - </section> + </section> <!-- We accept a name and find no result --> + + <section> + <title>We write our first implementation of the servlet</title> + <para> + So we've finally got our servlet doing nothing, so let's make it do what we need to get through the + first task. The first step is to extend our test with the output we expect to see: + </para> + <programlisting> +public void testNoEntries() throws ServletException, IOException { + <emphasis>final StringWriter page = new StringWriter();</emphasis> + + HttpServletRequest mockRequest = new NullHttpServletRequest() { + public String getMethod() { + return "GET"; + } + public String getProtocol() { + return "HTTP/1.1"; + } + }; + <emphasis>HttpServletResponse mockResponse = new NullHttpServletResponse() { + public PrintWriter getWriter() throws IOException { + return new PrintWriter(page); + } + };</emphasis> + + AddressBookServlet servlet = new AddressBookServlet(); + servlet.service(mockRequest, mockResponse); + + <emphasis>assertEquals("Should be empty response", "No address found", page.toString().trim());</emphasis> +}</programlisting> + <para> + The <classname>HttpServletResponse</classname> interface provides a <classname>PrintWriter</classname> that + the servlet can use to write out the page that it wants to send back to the browser. We've implemented this + by wrapping a <classname>StringWriter</classname> that's declared as a variable in the test. We can check + whether our servlet has written out something like the right page contents with a simple comparison at the end + of the test. We've also trimmed our output string to avoid disagreements over new lines. + Let's run the test. + </para> + + &redbar; + <screen> +There was 1 failure: +1) testNoEntries(nostone.addressbook.AddressBookServletTest) +AssertionFailedError: Response page expected:<No address found> but was:<> + at nostone.addressbook.AddressBookServletTest.testNoEntries(AddressBookServletTest.java:41) +FAILURES!!! +Tests run: 1, Failures: 1, Errors: 0</screen> + + <para> + Good, our test has failed. We haven't yet implemented the relevant method in the servlet, so let's + write just enough code to get our green bar back. + </para> + + <programlisting> +public class AddressBookServlet extends HttpServlet { + + <emphasis>protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + resp.getWriter().println( "No address found" ); + }</emphasis> +}</programlisting> + + &greenbar; + <para> + Now the test passes because the returned page matches the text we asked for — we said + <emphasis>just</emphasis> enough code to pass the test, and we meant it. There's one more thing missing + before we can sign off this task. The servlet response specification says that a servlet must set + the content type of the response before getting hold of a writer, and we have no test (and therefore no + implementation) for that. If we hold onto the content type in the mock response object, we can check that + it's been set before we get the writer. + </para> + + <programlisting> + HttpServletResponse mockResponse = new NullHttpServletResponse() { + <emphasis>private String contentType; + public void setContentType(String aContentType) { + contentType = aContentType; + }</emphasis> + + public PrintWriter getWriter() throws IOException { + <emphasis>assertNotNull("Should have content type", contentType);</emphasis> + return new PrintWriter(page); + } + };</programlisting> + + <para> + Of course this fails + </para> + + &redbar; + <screen> +There was 1 failure: +1) testNoEntries(nostone.addressbook.AddressBookServletTest) +AssertionFailedError: Should have content type + at nostone.addressbook.AddressBookServletTest$2.getWriter(AddressBookServletTest.java:33) + <emphasis>at nostone.addressbook.AddressBookServlet.doGet(AddressBookServlet.java:16)</emphasis> + at javax.servlet.http.HttpServlet.service(HttpServlet.java:740) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:853) + at nostone.addressbook.AddressBookServletTest.testNoEntries(AddressBookServletTest.java:39) +FAILURES!!!</screen> + + <para> + The interesting thing about this failure report is that it's our first example that fails + <emphasis>within</emphasis> the production code, not the test case. The stack trace shows + that we detected the failure in the middle of <methodname>doGet()</methodname> when the + servlet is getting hold of the writer. Let's fix the problem by setting the content type + as we're supposed to. + </para> + + <programlisting> +protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException +{ + <emphasis>response.setContentType("text/plan");</emphasis> + response.getWriter().println( "No address found" ); +}</programlisting> + + &greenbar; + + <para> + Done! Well, maybe not. One of us just noticed that we've set the content type to <quote>text/plan</quote>, + which is not what we meant. We want to test the value that we set for the content type as well. We could + just call <methodname>assertEquals("text/plain",...)</methodname> where now we call + <methodname>assertNotNull()</methodname>, but that wouldn't show us the failure until after it had + happened. Instead, we'll add an assertion to <methodname>setContentType()</methodname>. + </para> + + <programlisting> + public void setContentType(String aContentType) { + <emphasis>assertEquals("Content type", "text/plain", aContentType);</emphasis> + contentType = aContentType; + }</programlisting> + + &redbar; + <screen> +There was 1 failure: +1) testNoEntries(nostone.addressbook.AddressBookServletTest) +<emphasis>AssertionFailedError: Content type expected:<text/plain> but was:<text/plan></emphasis> + at nostone.addressbook.AddressBookServletTest$2.setContentType(AddressBookServletTest.java:28) + <emphasis>at nostone.addressbook.AddressBookServlet.doGet(AddressBookServlet.java:16)</emphasis> + at javax.servlet.http.HttpServlet.service(HttpServlet.java:740) + at javax.servlet.http.HttpServlet.service(HttpServlet.java:853) + at nostone.addressbook.AddressBookServletTest.testNoEntries(AddressBookServletTest.java:39) +FAILURES!!!</screen> + + <para> + Once again, our stacktrace shows us exactly where the failure happened and we can go straight in + and fix it. + </para> + + <programlisting> +protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException +{ + response.setContentType(<emphasis>"text/plain"</emphasis>); + response.getWriter().println( "No address found" ); +}</programlisting> + + &greenbar; + + <para> + Now we're ready for our first acceptance test. + </para> + </section> <!-- We write our first implementation of the servlet --> + + <!-- TODO --> <section> <title>accept a name and return a result from a hard-coded collection.</title> - </section> + </section> <!-- accept a name and return a result from a hard-coded collection --> <section> <title> @@ -169,7 +336,7 @@ Values are held in memory. </title> </section> - </chapter> + </chapter> <!-- Search for an entry in the book --> <chapter> <title>List all the entries in the book</title> |