|
|
||
Simon Brown's BlogProgramming ArchivesGlobal setUp() and tearDown() in JUnit testsPosted 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
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 CloverPosted 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 Here's a screenshot of the coverage report for some JSP custom tags that are part of a TagUnit test suite...
...looks like I still have more work to do. ;-) Displaying international characters in JSPPosted 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.
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 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 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 coveragePosted 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 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.
Here, an Using mock naming contexts for testingPosted 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
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 java.naming.factory.initial=some.package.mock.MockInitialContextFactory
At runtime, the call to | ||
|
|