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:

z = x + y

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.

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

This is easy enough to convert into a test case, as a subclass of GroovyTestCase.

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
    }
}

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:

protected def withBinding(Map map, Closure closure)

Therefore, if I extend GroovyShellTestCase, I can rewrite my test as:

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
    }
}

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. 🙂

About Ken Kousen
I teach software development training courses. I specialize in all areas of Java and XML, from EJB3 to web services to open source projects like Spring, Hibernate, Groovy, and Grails. Find me on Google+ I am the author of "Making Java Groovy", a Java / Groovy integration book published by Manning in the Fall of 2013, and "Gradle Recipes for Android", published by O'Reilly in 2015.

2 Responses to GroovyShellTestCase for testing Groovy scripts

  1. Sven Lehnert says:

    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. Florent Jaby says:

    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

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: