This week's book giveaways are in the Java EE and JavaScript forums.
We're giving away four copies each of The Java EE 7 Tutorial Volume 1 or Volume 2(winners choice) and jQuery UI in Action and have the authors on-line!
See this thread and this one for details.
The moose likes Struts and the fly likes Question on Unit Testing in Struts Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of The Java EE 7 Tutorial Volume 1 or Volume 2 this week in the Java EE forum
or jQuery UI in Action in the JavaScript forum!
JavaRanch » Java Forums » Frameworks » Struts
Bookmark "Question on Unit Testing in Struts" Watch "Question on Unit Testing in Struts" New topic
Author

Question on Unit Testing in Struts

Ryan Kade
Ranch Hand

Joined: Aug 16, 2005
Posts: 69
I don't know if this belongs more in the testing forum or the Struts forum, but this one moves quicker.

I am trying to understand how to test a specific (relatively simple) situation. I've scoured all kinds of unit testing articles and can't quite wrap my head around it. Namely, how do I create a mock (or a fake or a stub) for a dependency that instantiated within the method I'm testing?

For example, if I have a class:



There is no way that I can see in this methodology to substitute a mock MyInterfaceImpl for the "real" one.

I have read articles that recommend using Dependency Injection, which I would love to use, but I have a further problem: the ClassToBeTested is actually a Struts action. This means I don't get the luxury of adding constructors or Javabean setters to "inject" the dependency, right? I get one call to execute() with the standard 4 parameters, and that's it.

Abstracting the call out to a factory method doesn't help either. It just pushes the problem further down, because I still have to instantiate the Factory (or call a static method, heaven forbid).

It has also been suggested to me to go ahead and extract an interface for the dependency, and then create a second constructor to inject it. Struts would use the no-arg, and JUnit would use the second constructor. The problem is, I'm using StrutsTestCase and I don't believe it allows you control over which constructor gets called.

Anyone have some suggestions for this problem?

Thanks!
Ryan
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
One possibility would be to use a factory class. Example:


MyFactory class

[ January 17, 2007: Message edited by: Merrill Higginson ]

Merrill
Consultant, Sima Solutions
Ryan Kade
Ranch Hand

Joined: Aug 16, 2005
Posts: 69
Merrill,

Thanks for the response. I agree that's one way to do it. In fact, wrapping it with a factory may be the only way to do it given the way StrutsTestCase is set up.

I just hate to do it with an if statement like that. I'd like to leave all the test code in the JUnit test to keep things loosely coupled. But I can't figure out a way to inject my mocks/stubs into the Action class otherwise.

Anyone else faced this issue?
Brent Sterling
Ranch Hand

Joined: Feb 08, 2006
Posts: 948
I am not completely clear on the definitions of terms like Dependency Injection, Aspect Oriented Programming and Inversion of Control. From the little I know about Spring, it uses factories that are controlled by XML files. This seems like a cleaner approach than writing a bunch of factory classes in Java. I am not sure how easy it would be for you to implement something like this or integrate a third-party product to handle this.

I have written factories like Merrill's example. I have also had the build script copy the needed implementation class in place based on a build parameter. I would not say that I was 100% satisfied with either of these approaches.

- Brent
Ryan Kade
Ranch Hand

Joined: Aug 16, 2005
Posts: 69
Brent,

I agree with you ... the Spring style injection is very clean. However, though I'm relatively new to StrutsTestCase, I don't believe it supports it. There's no XML config files to speak of, and the framework doesn't allow you access to the Action class, and thus not to constructors, or any setters that might be defined (the two primary methods of DI).

I've been reading through some StrutsTestCase forum threads, and it looks like the only way to do this is through subclassing the MockStrutsTestCase itself, and overridding some of the methods to allow you access to the Action. While this works, it creates tight coupling to the internal StrutsTestCase architecture and may cause the tests not to work in future releases.

What it boils down to, I think, is that there is no optimal way provided by StrutsTestCase to do this without coding Merrill's suggestion. I find this to be quite unfortunate since it's otherwise a very useful testing framework. I'm surprised it hasn't been addressed before now.

Thanks for your help,
Ryan
[ January 18, 2007: Message edited by: Ryan Kade ]
Merrill Higginson
Ranch Hand

Joined: Feb 15, 2005
Posts: 4864
If you're willing to completely convert your entire project to integrate Spring, then you can do dependency injection in an action class. However, the steps to integrate Spring into Struts are not trivial, and it seems like overkill just to change an interface for testing purposes.

However, if you want to go that route, here's a good link explaining how to do it:

http://www-128.ibm.com/developerworks/java/library/j-sr2.html?ca=drs-tp4105
Ryan Kade
Ranch Hand

Joined: Aug 16, 2005
Posts: 69
Unfortunately Merrill that's not an option for this project, but could be something to look into in the future.

Given the limitations of StrutsTestCase in this regard, I think I've found the best case solution (although it's by no means optimal). I've chosen to subclass MockStrutsTestCase and make some modifications whereby I can specify my own Action class for a given path, rather than the one specified in struts-config.xml. That Action class will be a subclass of the one I'm trying to test, with the appropriate methods overridden to return test data.

This has a few limitations that I can see:

(1) It makes it impossible to test with multiple test data sets without either re-compiling or creating multiple subclasses of the Action class for each test.
(2) It requires that the methods in the test Action class (the parent) be protected or package-private, rather than private.
(3) It separates test code into two different locations, reducing clarity of intent.
(4) It ignores the RequestProcessor specified in struts-config.xml.

But, it does allow me to test my code without having special "if" statements buried in my business logic returning different values for test cases. And, it's pretty flexible in allowing me to specify any Action subclass I want to the ActionServlet. So, it will have to do for now.

I got the idea from the StrutsTestCase forums, if anyone is curious. It's given under the post by Dmitri.

http://sourceforge.net/forum/forum.php?thread_id=941422&forum_id=121751

Thanks for everyone's help!
Ryan

ActionSubclassMockStrutsTestCase
[ January 19, 2007: Message edited by: Ryan Kade ]
 
Don't get me started about those stupid light bulbs.
 
subject: Question on Unit Testing in Struts