GroovyShellTestCase for testing Groovy scripts

I try to keep up with developments in the Groovy and Grails worlds. I really do. I follow most of the core team members on Twitter. I listen to the Grails Podcast when I can. I go to many conferences and attend other talks when I’m not speaking. I try to follow the email lists, though they’re way too high volume. I even have a Google+ account, though I don’t check it very often.

It’s all too much, actually. As I get older, I find that keeping up isn’t just a question of time, it’s a question of energy. Sometimes I’ll manage to catch up on my Twitter feed and am too tired to do much else.

So new developments slip by me. I guess that’s good, since it’s indicative of an active ecosystem, but it can be frustrating at times.

The one that forms the subject of this blog post is pretty trivial and arguably not worth writing about, but I missed it when it first came out so I thought I’d document it here.

Say you have a script in Groovy and you want to test it. You can execute the script programmatically using GroovyShell, and supply any needed variables with an instance of the Binding class.

Here’s a trivial example. I have the following massively complex, powerful script:
[sourcecode language=”groovy”]
z = x + y
[/sourcecode]
Say this is saved in a file called ‘math.groovy‘. Since none of the variables x, y, and z are declared at all in the script (not even using def), they can be accessed through a Binding object.
[sourcecode language=”groovy”]
Binding binding = new Binding()
binding.x = 3; binding.y = 4
GroovyShell shell = new GroovyShell(binding)
shell.execute(new File(‘math.groovy’))
assert 7 == binding.z
[/sourcecode]
This is easy enough to convert into a test case, as a subclass of GroovyTestCase.
[sourcecode language=”groovy”]
class ScriptTests extends GroovyTestCase {
void testMath() {
Binding binding = new Binding()
binding.x = 3; binding.y = 4
GroovyShell shell = new GroovyShell(binding)
shell.evaluate(new File(‘math.groovy’))
assertEquals 7, binding.z
}
}
[/sourcecode]
By extending GroovyTestCase, this entire script can be executed at the command line or inside the Groovy Console without adding any additional library dependencies of any kind (not even JUnit). When I ran it, the result was:

.
Time: 0.037

OK (1 test)

That’s all well and good. I was writing up examples like this for my book (Making Java Groovy, available through the Manning Early Access Program at http://manning.com/kousen) and decided to look at the Groovy API for GroovyTestCase. Lo and behold, what do I stumble upon but a class called GroovyShellTestCase. The class was authored by Alex Tkachman (so you know it’s good :)), presumably back in 2008 if the copyright statement is to be believed. Of course, the copyright could just be a copy-and-paste issue*.

*Which is what I like to call the CAP Design Pattern — how to take an error in one small part of your system and distribute it throughout the entire code base.

The GroovyDocs are a bit thin on that class, but they say (and I quote), “GroovyTestCase, which recreates internal GroovyShell in each setUp()”. The class has a protected field called shell of type GroovyShell, and a method called withBinding with a couple of overloads. For my purposes, I want the overload that takes two arguments, the first being a Map of binding variables, and the second being a closure to be executed. The method executes the closure with the given binding:
[sourcecode language=”groovy”]
protected def withBinding(Map map, Closure closure)
[/sourcecode]

Therefore, if I extend GroovyShellTestCase, I can rewrite my test as:
[sourcecode language=”groovy”]
class ScriptTests extends GroovyShellTestCase {
void testMath() {
def result = withBinding( [x:3, y:4] ) {
shell.evaluate(new File(‘math.groovy’))
shell.context.z
}
assertEquals 7, result
}
}
[/sourcecode]
The map supplies x and y to the binding, which is automatically supplied to the instantiated shell. I can get the result by calling the getContext method on the shell (i.e., access the context property) which returns the binding, and then accessing its z property. I’m taking advantage of the fact that the implementation of the withBinding method includes “return closure.call()“, so the last evaluated expression in the closure is returned automatically.

This isn’t a huge deal, but it’s there and presumably it’s been there for a while and I never knew it. Now I know. Even better, now you know. Maybe you’ll have a use case that needs it. I’ve been trying to make sure that all my scripts in my book have test cases, and this gives me a convenient way to write them.

My only disappointment in discovering this is that when I looked for the tests for the GroovyShellTestCase class, I didn’t find any. In the Groovy distribution under src/test/groovy/util, there’s GroovyScriptEngineTest, GroovyTestCaseTest, and even GroovySwingTestCase, but no dedicated class for testing GroovyShellTestCase. Maybe that’s my opportunity to add one and make a (tiny, but useful) contribution to the language. That would be fund to do just to write a class called GroovyShellTestCaseTest. Heck, that’s only one small step away from the palindromic GroovyShellTestCaseTestShell.groovy. 🙂

2 responses to “GroovyShellTestCase for testing Groovy scripts”

  1. Hi Ken,
    I really like those small code snippets and your blog.
    I write a lot of small groovy scripts to make my daily work easier and now I (better) know how to test them painlessly without contaminating them!
    Thx a lot and keep writing!
    Regards, Sven.

    PS: I’m missing the +1 Button 😉

  2. Hello Ken,

    I stumbled upon your article when trying to test some custom score scripts for elasticsearch. This works great. I like very much the fact that I can just run `groovy myTest.groovy` to have my tests executed.

    However doing so always exits with code 0 on the shell. Do you have any idea how to make a failing test exit with a non-0 code ?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.