You want to write a test that submits your HTML forms and verifies the forms functionality.
Set parameters on the WebForm using its setParameter( ) method. Then simulate clicking a button by asking for one of the form's buttons and submitting it using the WebConversation instance.
You fill in form field values using the setParameter( ) method on a WebForm instance. This simulates what the user would do if he was filling out a form in a web browser. You then ask the form for a WebRequest object, passing in the name of one of the submit buttons. All of this is shown in Example 5-9.
public void testSubmitSubscriptionWithoutRequiredField( ) throws Exception { WebForm form = getBlankSubscriptionForm( ); form.setParameter("nameField", "Eric Burke"); WebRequest request = form.getRequest("subscribeBtn"); // Submit the page. The web app should return us right back to // the subscription page because the Email address is not specified WebResponse response = this.webConversation.getResponse(request); // make sure the user is warned about the missing field String pageText = response.getText( ); assertTrue("Required fields warning is not present", pageText.indexOf("Email address is required") > -1); // make sure the nameField has the original text form = response.getFormWithID("subscriptionForm"); assertEquals("Name field should be pre-filled", "Eric Burke", form.getParameterValue("nameField")); }
The comments in Example 5-9 explain what is expected at each step. The overall goal is to ensure that the form treats the email address as a required field. If the field is missing, the form should be redisplayed with an error message. When the form is redisplayed, the name field should be pre-filled with the previously entered value.
Example 5-10 shows the updated servlet. As is typical in a web application, the validation logic is contained within the servlet, rather than the JSP. Even better, you might want to refactor the validation logic into a helper class rather than the servlet itself. This step would allow you to write standalone tests against the validation logic without invoking the servlet. Once the request is fully validated, the servlet dispatches to the JSP for rendering.
public class NewsletterServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { dispatchToSubscriptionPage(req, res); } protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { if (req.getParameter("subscribeBtn") != null) { handleSubscribeButton(req, res); } else if (req.getParameter("unsubscribeBtn") != null) { // @todo - handle this later, but only after writing more tests } dispatchToSubscriptionPage(req, res); } private void dispatchToSubscriptionPage(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { RequestDispatcher dispatcher = req.getRequestDispatcher("subscription.jsp"); dispatcher.forward(req, res); } private void handleSubscribeButton(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String name = req.getParameter("nameField"); String email = req.getParameter("emailField"); // email is required if (email == null || email.trim().length( ) == 0) { req.setAttribute("errorMessage", "Email address is required"); dispatchToSubscriptionPage(req, res); } else { // @todo - subscribe the user! } } }
The NewsletterServlet is nearly at its final form. A doPost( ) method was added to handle the form submission, and the logic formerly found in doGet( ) has been refactored into the dispatchToSubscriptionPage( ) method. This refactoring avoids code duplication and is easily tested with the existing suite of unit tests.
Pay particular attention to the @todo comments. These indicate that portions of the code are not complete. With the test-first approach taken in this chapter, these pieces of functionality should not be written until the corresponding unit tests are written. You might also consider putting your @todo comments in your test cases, rather than in the code itself. This strategy provides stronger encouragement to focus on test-driven development when those features are eventually added.
|
Finally, Example 5-11 shows the revised JSP. The JSP now contains logic to display the error message attribute, which is sometimes provided by the servlet. It also pre-fills the value of the name field if necessary.
<html> <% String errorMsg = (String) request.getAttribute("errorMessage"); String name = request.getParameter("nameField"); if (name == null) { name = ""; } %> <head> <title>Newsletter Subscription</title> </head> <body> <h1>Newsletter Subscription</h1> <% if (errorMsg != null) { %> <font color="red"><%= errorMsg %></font> <% } %> <form method="post" action="subscription" id="subscriptionForm"> <table> <tr> <td>Name:</td> <td><input type="text" name="nameField" value="<%= name %>"></td> </tr> <tr> <td>Email:</td> <td><input type="text" name="emailField"> (required)</td> </tr> </table> <input type="submit" name="subscribeBtn" value="Subscribe"/> <input type="submit" name="unsubscribeBtn" value="Unsubscribe"/> </form> </body> </html>
At this point, the tests (including all of the old tests) should pass. It is also a good idea to try out the web app inside of a web browser to see if you forgot to test anything. The test-first process can continue until all of the functionality is implemented.
Recipe 5.8 and Recipe 5.9 show how to test other aspects of HTML forms.