Meaningless Drivel is fun!*
The moose likes Testing and the fly likes Working around dependencies Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Java 8 in Action this week in the Java 8 forum!
JavaRanch » Java Forums » Engineering » Testing
Bookmark "Working around dependencies" Watch "Working around dependencies" New topic
Author

Working around dependencies

Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 4419
    
    5

I'm finding out first-hand just how difficult it can be to test-drive development of a web-based application. I've read about techniques for working around dependencies on web containers and EJB containers and their services in a few articles and books and much of the advice has to do with mock objects. I've had very limited success with using these approaches. Here's why.

The application I'm working on has a lot of code generated by an MDA (model-driven architecture) tool. The tool generates a lot of fine-grained facade objects which developers currently call directly from Struts action classes. With this approach, it's difficult to write vanilla JUnit test cases since the generated facade directly accesses EJBs. CactusStrutsTestCase does help but using it slows down the TDD cycle considerably.

The tool generated facades are also concrete classes with many different methods and are a bit difficult to mock up because they keep track of the state of the objects that it returns from its methods (yeah, my reaction was "What the h...?!" too). For example:



This is a complete snippet: there are no statements between the calls to setXXX() and facade.store(). It is evident from the above code that the facade keeps a reference to the FooUpdateObject that it returned and to the composite objects as well. This makes it difficult to mock up a facade. Again, the facade and the update objects are concrete classes; it would have been easier to mock them up with EasyMock if they were interfaces, but they are not. Refactoring the facade and update objects is not an option either since they are tool-generated code.

So, my question is, is there some way for me to test-drive this stuff with just plain JUnit classes and POJOs or am I stuck with having to write in-container test cases?


Junilu - [How to Ask Questions] [How to Answer Questions]
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Uh, this sounds - well, less than optimal...

Can you perhaps change the way the MDA tool generates the code (isn't that what MDA is about)?


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 4419
    
    5

Originally posted by Ilja Preuss:
Uh, this sounds - well, less than optimal...


For a moment there I thought you'd somehow figured out what tool we were using... But you're right, it's far from optimal (ironically).

I'm sure there's a way to change the transformation patterns but we don't have that kind of expertise in-house. We're using the transformation patterns that come out of the box.

My initial efforts went something like this:

1. Created a coarse-grained facade (a POJO) so I could move a lot of processing logic out of the Struts action classes.
2. Created an Interface to abstract away the data input source.




The above refactoring allowed me to create a vanilla JUnit test:



The cast to (IFooCreateInput) is redundant because we made the form implement the IFooCreateInput, I'm just using it to show what the helper.create() method expects.

I suppose I could just bite the bullet and manually create an interface that reflects all the methods in FooFacade that I want to fake out. There's still the UpdateObjects though

One of the comments (complaints?) I hear most often is that having to mock up so many things just seems like a lot of hard work that has very little payoff and that we're having to write way too much test code for a very little amount of production code. This does not help ease the concern that the test-first approach will take away from the time we have to develop the production code. Despite my belief that the up-front effort to write test code will pay for itself down the road, I can't help feeling the same way sometimes. There has to be an easier way.

(BTW, I have found reflective articulation to be very helpful at times and part of the reason I'm writing all this is that I hope that by just doing so, it might help me to find an alternative solution. The main reason, of course, being that I hope to get some good advice from Ilja, Lasse and the other regulars. TIA )
Lasse Koskela
author
Sheriff

Joined: Jan 23, 2002
Posts: 11962
    
    5
It might be worth a shot to try MockEJB, deploying your own mock EJBs into a lightweight, in-process EJB container and letting the code under test do the JNDI lookup, invoke the EJB, etc.


Author of Test Driven (2007) and Effective Unit Testing (2013) [Blog] [HowToAskQuestionsOnJavaRanch]
Jeanne Boyarsky
internet detective
Marshal

Joined: May 26, 2003
Posts: 29287
    
140

Junilu,
How much of that code snippet is generated? We use the approach that if something is completely generated, it isn't necessary to write unit tests. After all, if you can't change the code, you can't break it. (There are some generated tests, but that's another story.)

Does the generator let you put your code in methods? If so, you can put your custom code in one testable method and let the generator do its thing.


[Blog] [JavaRanch FAQ] [How To Ask Questions The Smart Way] [Book Promos]
Blogging on Certs: SCEA Part 1, Part 2 & 3, Core Spring 3, OCAJP, OCPJP beta, TOGAF part 1 and part 2
Junilu Lacar
Bartender

Joined: Feb 26, 2001
Posts: 4419
    
    5

Jeanne,

The Facade and UpdateObjects are the generated classes. The tool does allow custom code to be added to the generated classes but it was decided by the team, due to some bad experiences and perceived flakiness of the tool, to just stick to generated code exclusively.

We're not writing tests for the generated code either, which is why we're trying to mock up the classes that are generated.
Jeanne Boyarsky
internet detective
Marshal

Joined: May 26, 2003
Posts: 29287
    
140

Junilu,
Yuck! One way to get around it is to write/generate a testable wrapper. Our code generator creates only static methods. One person wrote a wrapper that wraps each of those static methods with an instance method (and an interface) to make it testable.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Working around dependencies
 
Similar Threads
Refactoring Advice
Non J2EE transactional management in Java
unit testing struts?
Multiple inheritance
Learning Java and Agile Java