This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
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.
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.
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.
Joined: Aug 16, 2005
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 ]
Joined: Feb 15, 2005
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:
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.