The Artima Developer Community
Sponsored Link

Java Buzz Forum
Testing MVC actions, mock objects and code coverage

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Simon Brown

Posts: 636
Nickname: simonbrown
Registered: Jun, 2003

Simon Brown is a Java developer, architect and author.
Testing MVC actions, mock objects and code coverage Posted: Jan 21, 2004 9:31 AM
Reply to this message Reply

This post originated from an RSS feed registered with Java Buzz by Simon Brown.
Original Post: Testing MVC actions, mock objects and code coverage
Feed Title: Simon Brown's weblog
Feed URL: http://www.simongbrown.com/blog/feed.xml?flavor=rss20&category=java
Feed Description: My thoughts on Java, software development and technology.
Latest Java Buzz Posts
Latest Java Buzz Posts by Simon Brown
Latest Posts From Simon Brown's weblog

Advertisement

Mock objects are the subject of several blogs again this week and they reminded me of a question that several people have asked me. In a web application, how do you unit test an MVC action?

In a previous blog entry, I highlighted the differences between implementations of the Servlet specification when it comes down to security and presented a fairly simple workaround. Subsequently, I now have a class called LoginAction that looks something like this.

import ...;

public class LoginAction extends Action {

  /**
   * Peforms the processing associated with this action.
   *
   * @param request  	The HttpServletRequest instance.
   * @param response   	The HttpServletResponse instance.
   * @return       	The name of the next view
   */
  public String process(HttpServletRequest request,
                        HttpServletResponse response)
      throws ServletException {

    if (request.getUserPrincipal() != null) {
      // some J2EE web containers don't allow programmatic access to the
      // principal information from resources that don't fall under a
      // security constraint - for this reason this information is placed into
      // the user's session
      AuthenticatedUser user = new AuthenticatedUser();
      user.setName(request.getUserPrincipal().getName());
      user.setBlogOwner(request.isUserInRole(Constants.BLOG_OWNER_ROLE));
      user.setBlogContributor(request.isUserInRole(Constants.BLOG_CONTRIBUTOR_ROLE));
      request.getSession().setAttribute(Constants.AUTHENTICATED_USER, user);
    }

    try {
      response.sendRedirect(someUrl);
    } catch (IOException ioe) {
      throw new ServletException(ioe);
    }

    return null;
  }

So then, how do you test this? Well, the solution that I've adopted is to use mock objects. The reasons? I want to be able to run my unit tests quickly and without the hassle of setting up a web/application server environment and deploying my code into it. A mock object is effectively a stub for some code that is typically implemented elsewhere. In this example, I am choosing to mock out the interfaces provided by the Servlet specification and this entails providing dummy implementations for those interfaces. As with everything, there is some work involved in building these mocks, but thankfully there are several prebuilt mock object implementations available including MockObjects, EasyMock and JMock.

Back to the question in hand, with mock objects, testing the action class becomes fairly straightforward.

  public void testAuthenticatedBlogOwner() {
    try {
      MockPrincipal principal = new MockPrincipal("simon");
      principal.addRole(Constants.BLOG_OWNER_ROLE);
      request.setUserPrincipal(principal);
      String result = action.process(request, response);
      assertNull(result);
      assertEquals(someUrl, response.getSendRedirect());

      // and also check that an AuthenticatedUser object has been created
      AuthenticatedUser user = (AuthenticatedUser)request.getSession().getAttribute(
        Constants.AUTHENTICATED_USER);
      assertEquals("simon", user.getName());
      assertTrue(user.isBlogOwner());
      assertFalse(user.isBlogContributor());
    } catch (ServletException e) {
      fail();
    }
  }

Like crazybob, I've also taken the approach of generating mock objects using an IDE. With IntelliJ it's straightforward - just create a new class, state that it implements an interface and choose "Implement methods..." from the Code menu. You might ask why I'm not using a prebuilt implementation and the answer is that I just don't need the sort of flexibility that they offer. The code I'm testing only uses a very tiny percentage of the Servlet API and I can easily generate my own simple mocks very quickly using a YAGNI approach. The existing mock object implementations have support for automatic verification, method invocation counts and so on. There's some really clever stuff in there, but I just don't need it ... yet. ;-)

Mock objects present an easy way of testing this MVC action and provide a way to test that action outside of the container. MVC actions are often one of the hardest parts of a web application to test, and using mock objects makes testing easier which in turn helps ensure confidence in your code. Saying this though, one thing still eludes me.

Clover running in IntelliJ IDEAIn an ideal world, everybody would aim for 100% unit test code coverage all of the time. In reality I don't think that this is possible. If you look back to the action code above, there is one part that typically won't be executed (see image).

Here, an IOException is thrown if there is a problem in redirecting the response. For example, part of the response could have already been committed. In the normal course of testing this action, that line of code will never get called. Of course, since I'm using mocks, I could write some code to cause that method to throw the relevant exception and acheive the full 100% code coverage but I'm not convinced that this necessarily provides any additional benefit or confidence that this piece of code will work as expected. This is just one example but what do you think? Would you put extra effort into testing this line of code to acheive 100% test coverage? If not, when do you know when to stop. I guess that at the end of the day, it's all about confidence and what works for you. I'd be interested to hear your thoughts on this.

Read: Testing MVC actions, mock objects and code coverage

Topic: Corect Speling Previous Topic   Next Topic Topic: JBoss and Guerilla Marketing: Richard Saunders

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use