{{ !articles[0].partner.isSponsoringArticle ? "Platinum" : "Portal" }} Partner
java,agile,frameworks,testing,tdd,tools & methods

Testing Code Generation

Some things lend themselves to TDD better than others. Code generation, it turns out, scores a 10 on this front. (To some people, it‘s heresy to think that one should favor one approach over another based on the ease of development; I would disagree with this. When a factory tools up to make a product, it‘s all about whether they can get to a production level where they are rolling off the line for an amount where the things can be sold and a profit made. In development, we act like we can‘t really see into that dimension, so there‘s no real reason to try, and oh, yer stuff will be done when it‘s done. Estimates are NOT just about feature density. As a matter of fact, the feature line that each thing must travel will, by definition, impact all features.)

Anyway, using JUnit 4, and running plugin tests that restart the whole environment is as good as things get in terms of using TDD to really leverage agility on the dev side. You can do whacky refactors and just rerun the suite and never have to bring up an app and run through a bunch of steps, and wonder if you can trust yourself to check that each thing was done right. In code gen, all there is is the code that was generated. (Of course, one of the questions that pops out of this is how far into the mine do the savings extend. In other words, will there just be benefits to this while building up the base set of templates and the things they generate, or will we find ourselves, as we get farther into projects, returning to the gen code to augment what is coming out? I am starting to think the latter, because already I am seeing things that make a lot of sense, like generating global search, generating QBE classes, etc.

The first set of tests for checking whether code generation was done properly required the creation of a dummy project (used the Gamma/Beck code that they dropped with their book 5 years ago [fixed all the deprecations and added a few new things]), and then created an action and invoked it. The core generation outputs the properties files, the controllers (for create, update), the repository classes, the facelets, and a search page. So that test got pretty big, checking to see if all those things were generated, then looking at their contents. Then I set out to make it possible to gen QBE, and figured, since you are not going to want that for every entity, that should be a separate action. I was able to make another action to invoke pretty easily doing a cut and past in plugin.xml and then making a new handler class. Then I refactored the handler, figuring since there are going to be a number of actions that do the same thing (take a folder of templates and generate a bunch of code), might as well have a baseclass that does that. Once I was done with that I started working on the test of the new action. Then I realized that the only thing that‘s going to be different in these tests is what the action class is, so I ended up with the following construct: a base class that is abstract that does the project fixture, the action invocation, then the teardown, and the derived class just calls super, passing the class of the action. Here‘s what it looks like:

First the base class. Notice the action is just made by taking the class that was passed to the constructor and calling newInstance() on it (and note that we only have to reference it through the eclipse delegate interface):

then the action-specific tests:

The nice thing is that as people add new generation tasks, they can just completely ignore the project fixture requirements, just create a new test and start checking for their results. (Made me ponder for a moment how anyone would have an excuse for not doing a test in such circumstances….)

From http://www.jroller.com/robwilliams

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks