The field of Java™-based web development has recently emerged as a rich competitive technology. Developers who start new projects can choose between many different frameworks, including JavaServer Faces, Tapestry, Shale, Grails, and Seam (just a few of the clever names listed). Soon, we can use Ruby on Rails in Java programming via the JRuby framework!
But in the near past, there is only one Java Web development framework. Struts was the first framework to storm the Java world, and for years it seemed as if a project would have no future without Struts. Java developers without Struts experience are rare and unfortunate, as today's developers have not heard of Ruby on Rails.
Even though struts is slowly retreating from the center of the stage (the original basic framework, now called Struts 1, seems to be exiting the historical arena of the WEB framework), its legacy still exists, both in the form of Shale and in the form of thousands of legacy applications running around the world. Because many companies prefer to test and maintain these applications rather than spend money to rewrite them, it's a good idea to understand some of the drawbacks of the Struts application and how to refactor around them.
This month, I'm going to use a quality-focused approach to test scenarios for Struts applications. Combined with reality, this scenario revolves around the most common Struts structure: the beloved Action class.
1, 2, 3, action!
One of the innovations of Struts is to move Web development from the Servlet to the Action class. These classes contain business logic that transmits data to the JSP in the form of JavaBean (often called actionform). The JSP then processes the application view. The method of Struts to MVC is so easy to grasp that many development teams take the risk of losing ground and rarely consider long-term design and maintenance issues related to Action.
Testing and complexity
I have found a strong correlation between developer testing and the complexity of the code: there is no one, and there is usually no other. Highly complex coding is difficult to test, and the result is that very few people actually write tests for it. In turn, writing tests can reduce the complexity of your code. Because it's more difficult to write tests for complex code, and because of the walking test, you'll find yourself moving toward simpler code constructs. If your code is too complex and you know you have to test it, you may be refactoring the complexity before you test it. Regardless, writing tests for less-than-simple code is a good practice for eliminating code complexity.
Although at that time (the past free time) may not have been thought of, but the Struts Action class is often the protection of complexity. Like the infamous session façade in the old EJB architecture, the Action class becomes a strict camouflage for a particular business process, either by opening a database connection by invoking the EJB directly, or by invoking other highly dependent objects. The Action class also has output coupling (through the objects in the Java.servlet API package, such as HttpServletRequest and HttpServletResponse), making it extremely difficult to isolate them for testing.
The difficulty of isolating them to test Action classes means that they can easily become quite complex-especially when they become more and more deeply coupled to the legacy framework. Now let's look at the situation where this difficulty works in a real legacy application scenario.
Test challenges
Even the simplest Struts Action class can be a test challenge. For example, take the Execute () method in Listing 1 as an example; it looks simple enough to test, but really?
Listing 1. This method looks easy to test ...
public ActionForward execute(ActionMapping mapping, ActionForm aForm,
HttpServletRequest req, HttpServletResponse res) throws Exception {
try{
String newPassword = ((ChangePasswordForm) aForm).getNewPassword1();
String username = ((ChangePasswordForm)aForm).getUsername ();
IUser user = DataAccessUtils.getDaos().getUserDao ().findUserByUsername(username);
user.digestAndSetPassword(newPassword);
DataAccessUtils.getDaos().getUserDao().saveUser(user);
}catch(Throwable thr){
return findFailure(mapping, aForm, req, res);
}
return findSuccess(mapping, aForm, req, res);
}
Figure 1. Output coupling of Action class
However, as you can see in Figure 1, this class presents some representative challenges when trying to isolate the Changepasswordaction class and examine the Execute () method. In order to effectively test the Execute () method, you must handle three-layer coupling. First, the coupling to Struts itself; second, the Servlet API represents an obstacle; Finally, to the coupling of the business object package, further examine the business object package, and there will be a data access layer using Hibernate and Spring.