The Source for Java Technology Collaboration
User: Password:



Simon Brown's Blog

Programming Archives


Global setUp() and tearDown() in JUnit tests

Posted by simongbrown on April 16, 2004 at 02:43 PM | Permalink | Comments (5)

Like many people, I want a way to run some one-time set up and tear down logic and the approach I usually take is to drop some code into a static initializer block in an abstract test case. For example...

public abstract class SomeTestCase extends TestCase {

  static {
    // perform the "global" set up logic
  }

}

Providing that I remember to subclass SomeTestCase then this approach works well. So that's set up covered, but what about tear down? Simple - just use a JVM shutdown hook.

public abstract class SomeTestCase extends TestCase {

  static {
    // perform the "global" set up logic

    // and now register the shutdown hook for tear down logic
    Runtime.getRuntime().addShutdownHook(new SomeTestCaseShutdownHook());
  }

}

This is quite a simple solution and is an alternative to the TestSetup class. As an example, I use it for creating a file structure on disk prior to running some tests and deleting that structure when the tests have run. The only caveat with this solution is that when you run your unit tests through Ant, the Ant ClassLoader executes the static initializer (and resets static variables) more than once. I don't know quite why it does this but if your global set up and tear down logic can safely be run more than once then it's not too much of a problem. Incidentally, this technique runs really well with the IntelliJ JUnit runner.



TagUnit and code coverage with Clover

Posted by simongbrown on March 24, 2004 at 01:25 PM | Permalink | Comments (0)

I've been using Clover for a few months now, but only in the context of my standalone JUnit tests and mainly from within IntelliJ IDEA. Having played with the Clover/Ant integration over the past few days, as with the IDEA integration, I can safely say that getting coverage reports for your unit tests is remarkably easy. Although I've known that it was possible, I've never tried running the instrumented code (that Clover generates) inside a J2EE container. So, to satisfy my curiosity, after a quick bit of Ant hacking the instrumented code was running inside Tomcat and updating the coverage database while my TagUnit tests were running.

It's really simple to do too - just build the instrumented classes into your normal JARs and deploy as usual. The only gotcha is that the coverage data doesn't always get written to disk until the JVM shuts down. Of course, you can fix this with the flushinterval attribute of the <clover-setup> Ant task.

Here's a screenshot of the coverage report for some JSP custom tags that are part of a TagUnit test suite...

Code coverage results for some TagUnit tests

...looks like I still have more work to do. ;-)



Displaying international characters in JSP

Posted by simongbrown on March 03, 2004 at 02:18 PM | Permalink | Comments (13)

I've been having lots of "fun" over the past days trying to figure out how to get JSP pages to properly display international characters. I've tried HTTP meta tags, JSP page encodings and seemed to be getting nowhere. If I have understood all the reading that I've done, then there are a couple of things that you should do to tell the web browser that you wish to display international (e.g. Japanese) characters.

  • Specify the content type and character set from within your JSP.
    <%@ page contentType="text/html; charset=UTF-8" %>
  • Use a HTTP meta tag as a hint to the browser (I don't think this is essential, but it all helps).
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

After trying this and seeing that it worked for most people, I was kind of confused to see that my pages still displayed international characters as junk. I checked and double-checked all my headers, flushed my browser caches and even tried it on different browsers (IE and Safari on Mac). Still no joy. In fact, looking at the character encoding of the page under IE revealed that the encoding was still Latin1.

After scanning around for anything else that looked remotely locale oriented, I realised that I was using the JSTL <fmt:setLocale> tag to set a default locale to be used within the <fmt:formatDate> tags. Changing the value of the locale passed through to this would change the actual character encoding of the web page. However, still the characters showed as junk, albeit different junk!

A quick scan through the JSTL specification for the <fmt:setLocale> tag revealed the answer (or at least what seems to be the answer).

As a result of using this action, browser-based locale setting capabilities are disabled.
I downloaded the code for the JSTL tags and using this tag does in fact set the locale of the response, which appears to take precedence over the above charset settings. Commenting this tag out fixed all the problems. Except one ... now my dates were all formatted according to the default locale of the JVM and the JSTL <fmt:formatDate> tag doesn't allow you to specify a locale purely for formatting purposes. Thankfully, you can set a default locale to be used in the formatting actions with the following code that uses the javax.servlet.jsp.jstl.core.Config class.
  Config.set(request, Config.FMT_LOCALE, someLocale);

Now there was just one last thing - submitting information via a HTML form. Most browsers don't appear to send back a charset in the request that corresponds to the encoding that was used to format the page. In this case, the request character encoding defaults to ISO-8859-1 meaning that there's potentially a mismatch between form data being sent (in UTF-8) and information retrieved from the request (in ISO-8859-1) using the getParameter() method on the HttpServletRequest class. To fix this, all you need to do is explicitly set the character encoding of the request before accessing data.

  request.setCharacterEncoding("UTF-8");

Is this the total solution to displaying international characters in JSP? I hope so but I need to test this on other platforms and JSP containers. Hopefully I will read this blog entry next week and everything will still be correct.



Testing MVC actions, mock objects and code coverage

Posted by simongbrown on January 21, 2004 at 08:41 AM | Permalink | Comments (18)

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.



Using mock naming contexts for testing

Posted by simongbrown on November 21, 2003 at 06:48 AM | Permalink | Comments (7)

Say for example that you want to unit test a Service Locator - a class that looks up data sources, topics, queues, etc from JNDI. How would you go about doing this?

One option would be to simply setup a JNDI environment inside a J2EE application server and write some JUnit tests to run inside the container. While this works, ideally you may want your unit tests to run independently and quickly.

The option we've just taken is to use a Mock Objects approach, therefore enabling us to run the tests during our normal unit test cycle. The one tiny problem that we ran into was that the service locator itself is responsible for creating a naming context by creating a new InitialContext instance, meaning that it's harder to get a mock context in there. The solution? Just write a mock InitialContextFactory as follows.

import javax.naming.Context;
import javax.naming.spi.InitialContextFactory;

/**
 * Provides a JNDI initial context factory for the MockContext.
 */
public class MockInitialContextFactory implements InitialContextFactory {

    public Context getInitialContext(Hashtable env) {
        return new MockContext();
    }

}

Then, when you want to run your tests, just stick a jndi.properties file on your classpath like this.

java.naming.factory.initial=some.package.mock.MockInitialContextFactory

At runtime, the call to new InitialContext() uses the mock factory and results in the creation of a mock context. Just remember not to deploy the properties file in production!





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds