Creator of the Apache Tapestry web application framework and the Apache HiveMind dependency injection container. Howard has been an active member of the Java community since 1997. He specializes in all things Tapestry, including on-site Tapestry training and mentoring, but has lately been spreading out into fun new areas including functional programming (with Clojure), and NodeJS. Howard is a DZone MVB and is not an employee of DZone and has posted 81 posts at DZone. You can read more from them at their website. View Full User Profile

Groovin' on the Testin'

08.25.2010
| 7332 views |
  • submit to reddit

I'm at the point now where I'm writing Groovy code for (virtually) all my unit and integration tests. Tapestry's testing code is pretty densely written ... care of all those explicit types and all the boilerplate EasyMock code.

With Groovy, that code condenses down nicely, and the end result is more readable. For example, here's an integration test:

    @Test
void basic_links() {
clickThru "ActivationRequestParameter Annotation Demo"

assertText "click-count", ""
assertText "click-count-set", "false"
assertText "message", ""

clickAndWait "link=increment count"

assertText "click-count", "1"
assertText "click-count-set", "true"

clickAndWait "link=set message"

assertText "click-count", "1"
assertText "click-count-set", "true"
assertText "message", "Link clicked!"
}


That's pretty code; the various assert methods are simple enough that we can strip away the unecessary parenthesis.

What really hits strong is making use of Closures though. A lot of the unit and integration tests have a big setup phase where, often, several mock objects are being created and trained, followed by some method invocations on the subject, followed by some assertions.

With Groovy, I can easily encapsulate that as templates methods, with a closure that gets executed to supply the meat of the test:

class JavaScriptSupportAutofocusTests extends InternalBaseTestCase
{
private autofocus_template(expectedFieldId, cls) {
def linker = mockDocumentLinker()
def stackSource = newMock(JavaScriptStackSource.class)
def stackPathConstructor = newMock(JavaScriptStackPathConstructor.class)
def coreStack = newMock(JavaScriptStack.class)

// Adding the autofocus will drag in the core stack

expect(stackSource.getStack("core")).andReturn coreStack

expect(stackPathConstructor.constructPathsForJavaScriptStack("core")).andReturn([])

expect(coreStack.getStacks()).andReturn([])
expect(coreStack.getStylesheets()).andReturn([])
expect(coreStack.getInitialization()).andReturn(null)

JSONObject expected = new JSONObject("{\"activate\":[\"$expectedFieldId\"]}")

linker.setInitialization(InitializationPriority.NORMAL, expected)

replay()

def jss = new JavaScriptSupportImpl(linker, stackSource, stackPathConstructor)

cls jss

jss.commit()

verify()
}

@Test
void simple_autofocus() {

autofocus_template "fred", {
it.autofocus FieldFocusPriority.OPTIONAL, "fred"
}
}

@Test
void first_focus_field_at_priority_wins() {
autofocus_template "fred", {
it.autofocus FieldFocusPriority.OPTIONAL, "fred"
it.autofocus FieldFocusPriority.OPTIONAL, "barney"
}
}

@Test
void higher_priority_wins_focus() {
autofocus_template "barney", {
it.autofocus FieldFocusPriority.OPTIONAL, "fred"
it.autofocus FieldFocusPriority.REQUIRED, "barney"
}
}
}

That starts being neat; with closures as a universal adapter interface, it's really easy to write readable test code, where you can see what's actually being tested.

I've been following some of the JDK 7 closure work and it may make me more interested in coding Java again. Having a syntax nearly as concise as Groovy (but still typesafe) is intriguing. Further, they have an eye towards efficiency as well ... in many cases, the closure is turned into a synthetic method of the containing class rather than an entire standalone class (the way inner classes are handled). This is good news for JDK 7 ... and I can't wait to see it tame the class explosion in languages like Clojure and Scala.

References
Published at DZone with permission of Howard Lewis Ship, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

King Sam replied on Fri, 2012/02/24 - 10:07am

In my journey into Spring, which certainly has a mass of good documentation and copious good examples which I am using, what I do not find is quite this level of interest in
a. abstraction
b. succinctness
c. meta patterns - generalisation

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.