|
|
||
Simon Brown's BlogOpen Source ArchivesTesting 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 Reasons to use Eclipse and SWT?Posted by simongbrown on November 14, 2003 at 09:19 AM | Permalink | Comments (18)I popped down to the JSIG today, the topic of which was Eclipse. Unfortunately I had a 2pm meeting so could only stay for the first presentation by Berthold Daum (author of Eclipse for Java Developers) which was an overview of Eclipse, SWT and plugin development. The first part of the session took a look at Eclipse itself, and Berthold gave a good overview of the tool, the workbench, the various views, perspectives and so on. Following on from this was a look at some of the features that Eclipse provides including things like code completion, code assist, refactoring, etc. Overall this was technically a good presentation although it didn't leave me wanting to download the tool and give it another try. If you've been following my blog, you'll know I'm a big fan of IntelliJ IDEA and I have a personal license to prove it. In terms of the content covered in the presentation, feature for feature there's nothing new that I can't do with IDEA. Apart from the obvious advantage (i.e. price), why should I switch to Eclipse? The next part of the presentation looked at SWT - the Swing alternative that Eclipse uses and that we (as developers) can use to build our own desktop applications. Again, this was a good presentation that covered topics ranging from the SWT architecture to the various widgets it provides. For me, the interesting part of the presentation was the summary of the pros/cons for using SWT. Advantages quoted include richer (native) widgets and integration, more stable and more responsive than Swing. Disadvantages quoted include SWT only runs on a limited number of platforms, widgets (can) have different behaviour on different platforms and deployment is an issue because of the native code. So, to summarise my understanding, SWT takes all the things that Java tries to achieve (platform independence, compatibility, etc) and throws them out of the window for something that is perceived to be faster, richer and more stable than Swing? I think I need some more convincing, particularly with the advances that J2SE 1.4.2 has provided in this area. Just as a last point, there was a quick poll done about how many people have used Eclipse and, unsurprisingly, about half of the audience (about 40 people) raised their hands. Whether you like it or not, Eclipse is gaining a large "market" share. There's been a lot of discussion about Eclipse/SWT, but why should developers make the switch to either of these two tools? Panther ships with Ant, XDoclet and JBossPosted by simongbrown on October 28, 2003 at 07:53 AM | Permalink | Comments (4)I've just installed Panther and since you don't get stuff like CVS installed by default, I decided to open up the XCode CD and install the developer tools. To my surprise there are some Java tools tucked away including Ant, XDoclet, log4j and JBoss. If you install the Java tools, they can be found in :
In Apple's inevitable way, running JBoss is as simple as navigating to the I knew that the server editions of Panther were going to include JBoss, but not the normal editions. Of course, you can already get newer versions of the tools yourself, but it's nice to see Apple making this stuff available and pushing Java as one of their development platforms. It just enables people to get up and running quickly, meaning that they can concentrate on learning how to develop applications rather than setting up tools. I wonder if we can convince Microsoft to include J2SE and Tomcat in the next edition of their OS? ;-) XDoclet in the J2EE web tierPosted by simongbrown on October 16, 2003 at 03:18 AM | Permalink | Comments (10)It's common that you'll find somebody using XDoclet to help build their EJBs, but how often do you find people using it to help with the J2EE web tier? In his recent weblog, Dave says he is trying to convince his team that using XDoclet is the way to go for generating artefacts like tag library descriptors and the web.xml file. I must admit that while XDoclet is very useful when building EJBs, I'm not sold on the idea of using for the web tier myself. Why? Well, I think that there are several reasons for this. For each EJB, you have to build 3 classes and the ejb-jar.xml file - all of which can be automated with XDoclet and a single source file representing the bean implementation. This is nice because the remembering all that nasty EJB deployment descriptor stuff is a pain, and everybody knows it's a pain. In one of the JavaOne sessions that I went to this year, the EJB team talked about how they were thinking of taking advantage of the new J2SE 1.5 (Tiger) feature of annotations/metedata (JSR-175) so that the deployment descriptors were automatically generated. Basically this would make XDoclet-like, attribute-oriented programming available to the J2EE platform, and that can't be a bad thing. Another reason to use XDoclet is so that package and class names are kept in sync between the Java source and the deployment descriptors. However, when you use tools like IntelliJ to refactor a class/package name, you can ask it to look in other files too so you get the deployment descriptor refactoring for free. I do like using XDoclet for generating the EJB stuff, but for me it doesn't add much for the web tier technologies. Are you using XDoclet in your J2EE apps? I'd be interested to hear from anybody with thoughts on this. Integrating Tomcat and Apache on Mac OS XPosted by simongbrown on October 13, 2003 at 02:24 PM | Permalink | Comments (3)I've been looking at integrating Apache and Tomcat on my PowerBook so that my dev environment more closely matches the box hosting my domain. Although I really do like open source, one of the biggest problems for me is that I always seem to need software that I have to build from the original source. This is one of the reasons I bought a Mac. I have tried running some of the various Linux distros (e.g. RedHat and Mandrake) and every bit of my hardware seems to need drivers and kernels recompiled. Not my idea of fun! Anyway, after a quick Google, I came across an article on the MacDevCenter entitled Integrating Tomcat with Apache Via the mod_jk Module. Admittedly it is slightly out of date with respect to the versions of Tomcat and mod_jk available, but the instructions do work and it has a link to download a prebuilt version of mod_jk for Mac OS X. Five minutes is all this took to get running and I didn't even have to recompile anything! How do you test tag libraries?Posted by simongbrown on October 07, 2003 at 11:58 AM | Permalink | Comments (6)Matt is looking for a way to test tag libraries and rather than write a lengthy comment, I thought I'd follow it up here. In the first part of his post, Matt says, ... I've looked briefly at TagUnit, but aren't you just writing JSPs (with custom tags) to test JSPs? In answer to this question, yes, you're exactly rght in saying that you're just writing JSPs. This is the essence of TagUnit, and why I believe it's a better way to test tags than using something like Cactus. Sure, you can test the various classes with JUnit, but since you don't use the classes in this way from a JSP page, this approach can only take you so far. JSP tags are reusable components and I think that they should be tested as such. For me, this means testing those tags in the same way that they will be used on a JSP page, and that's by writing the tests and assertions as JSP pages. Doing this has several benefits. First of all, you don't have to start mocking out parts of the servlet specification just to test the tag handlers. Instead, you're running the tests inside a real server. If you've looked into the JSP specification, you'll know that the tag lifecycle is a tricky business because of the way that JSP containers can optionally reuse and pool tag handler instances. By writing your tests as JSP pages, you instantly get all this framework for free, meaning that you can accurately test the behaviour on your desired target platform. Also, if you're aiming for cross-container compatibility, this is as simple as (in theory!) just dropping the WAR file containing the tests into a new container. Matt wants an Ant/JUnit solution and I can see why this is desirable. I'm far more likely to run the tests if I don't have to keep starting up the JSP container. Unfortunately, there aren't many ways around this without exploring avenues such as mock objects. However, TagUnit does provide an Ant task that can be used to initiate and collect the results of running the JSP-based tests. The basics of this are documented, although this document is being expanded as we speak ... isn't it Sam? ;-) As for whether there are HTML versions of the docs ... not yet, but there might be one day. I should probably add a disclaimer at this point, and highlight the fact that I created the TagUnit project. Clearly I'm biased, but I do think that it provides an improved way to test custom tags. Whether it's better ... that's for you to decide. HttpClient - another great Jakarta Commons componentPosted by simongbrown on October 06, 2003 at 12:58 PM | Permalink | Comments (9)
I was putting TrackBack support into Pebble the other day and the found that the technical details of a TrackBack involve sending a HTTP POST request to the remote server. I've implemented HTTP POSTs before using the classes in the
The following code shows how easy it is to make a HTTP POST with some
HttpClient httpClient = new HttpClient();
PostMethod postMethod = new PostMethod(url);
NameValuePair[] data = {
new NameValuePair("name1", value1),
new NameValuePair("namen", valuen)
};
postMethod.setRequestBody(data);
int responseCode = httpClient.executeMethod(postMethod);
String responseBody = postMethod.getResponseBodyAsString();
As you can see, there's not much code here at all, and HTTP GETs are easier still! From start to finish, making use of this component took about five, maybe ten, minutes. If you find you need to access HTTP-based resources, take a look at HttpClient. Installing Tomcat 4 as an NT servicePosted by simongbrown on September 26, 2003 at 03:57 AM | Permalink | Comments (18)While Matt was talking about the Tomcat Service Manager, coincidentally, I was trying to install Tomcat 4 as a service on a Windows 2000 machine yesterday. For various reasons, I didn't want to install Tomcat via the .exe and therefore had to hunt around for the command line that installs the NT service. For (my) future reference, here it is, split over several lines for readability. set JAVA_HOME=c:\j2sdk1.4.2_01 set CATALINA_HOME=c:\jakarta-tomcat-4.1.27 %CATALINA_HOME%\bin\tomcat -install "Jakarta Tomcat 4" %JAVA_HOME%\jre\bin\server\jvm.dll -Djava.class.path=%CATALINA_HOME%\bin\bootstrap.jar;%JAVA_HOME%\lib\tools.jar -Dcatalina.home=%CATALINA_HOME% %CATALINA_OPTS% -Xrs -start org.apache.catalina.startup.Bootstrap -params start -stop org.apache.catalina.startup.Bootstrap -params stop -out %CATALINA_HOME%\logs\stdout.log -err %CATALINA_HOME%\logs\stderr.log | ||
|
|