Dynamic closure argument types to test types that may not exist yet

Dynamically typed languages like Groovy are great for unit testing because they can be used to test different versions of the same library and adapt the test suite to the peculiarities of each library version at runtime and not fail completely if the interface doesn’t conform.

For instance, suppose I’ve written test cases to test the class Point, which is defined as the following:

public class Point {
  public final double x;
  public final double y;
  public Point(
      final double x,
      final double y) {
    this.x = x;
    this.y = y;

  public double distance(
      final Point that) {
    final double dx = this.x - that.x;
    final double dy = this.y - that.y;
    return Math.sqrt(dx * dx, dy * dy);

In Groovy, I could test it like this:

def test_distance_method() {
  def point1 = new Point(0.0, 0.0)
  def point2 = new Point(3.0, 4.0)
  Assert.equals(5.0, point1.distance(point2))

But what if distance is a planned method and doesn’t exist yet and we want to write the test case first but still be able to run the whole test suite without compilation errors?

That’s fine too because the distance method doesn’t need to exist. Groovy will compile it all the same and when it gets to running the code, checks to see if the method exists and if it doesn’t throw an exception. This allows other test cases to run unaffected.

This is great for methods but what about types? What if we don’t yet have a Point class but want to write test cases for it right away?

Not a problem. Just use reflection to create the class and its object:

def test_distance_method() {
  final pointClass = Class.forName("Point")
  def point1 = pointClass.newInstance(0.0, 0.0)
  def point2 = pointClass.newInstance(3.0, 4.0)
  Assert.equals(5.0, point1.distance(point2))

Groovy also has the ability to define new methods on existing classes. For instance we can add an overloaded write method to the DataOutputStream class to support our Point class:

DataOutputStream.metaClass.write << {
    final Point point ->

The above code defines a new closure (a bit like an anonymous function), then registers it for the DataOutputStream class using the << operator DataOutputStream when it is called.

This won’t be recognised in Java so Java code can’t use it, but the method is intended to be part of the test suite to help make writing test cases easier and the test suite is in Groovy, which can access the new method, so that’s not a problem:

final DataOutputStream os = new DataOutputStream(....)
os.write(Point.newInstance(0.0, 0.0))

Groovy knows to call our closure and not the built in Point.write(int) method because our closure was specified to accept arguments of the Point class. Overloading just works even if we have added the method dynamically.

Awesome huh?

But wait. The Point doesn’t exist yet. We haven’t written it.

DataOutputStream.metaClass.write << {
    final Point point -> // TYPE ERROR!

Groovy will barf because we’ve used the Point class directly in our code despite it not existing yet. What to do?

Removing the Point type in our closure definition doesn’t help because then the closure is untyped and overloading stops working properly.

We need to some how add type information to our closure without using the Point class directly.

Groovy doesn’t allow us to use variables in place of types:

def pointClass = Class.forName("Point")
DataOutputStream.metaClass.write << {
    final pointClass point -> // SYNTAX ERROR!

So that’s not an option.

Another possibility is to use Eval.me(), which is similar to the Javascript eval function. It compiles and runs code that is in a string:

DataOutputStream.metaClass.write << Eval.me("""{
    final Point point ->

Unfortunately, putting everything in a string is not ideal. It means that the compiler can’t check my code for syntax errors and IDEs can’t work with code inside strings either.

Fortunately, the Groovy runtime is written in Java and it is possible to extend the Closure class to have the type information we want.

The important method we need to implement is Closure.getParameterTypes(), which is the method that tells Groovy what the types of the parameters of our closures are so that it can find the correct overload to invoke.

Here is the code:

public final class RetypedClosure extends Closure {
  private final Closure closure_
  private final Class[] types_
  public RetypedClosure(
      final Closure closure,
      final Class[] types) {
    closure_ = (Closure)this.owner
    types_ = types
  public void setDelegate(
      final Object delegate) {
  public Object getDelegate() {
    return closure_.getDelegate()
  public void setResolveStrategy(
      final int resolveStrategy) {
  public int getResolveStrategy() {
    return closure_.getResolveStrategy()
  public Object clone() {
    return new RetypedClosure(closure_, types_)
  public Class[] getParameterTypes() {
    return types_
  public Object doCall(Object... args) {
    return closure_.getMetaClass().invokeMethod(
     closure_, "doCall", args)

def retype(final List types, final Closure closure) {
  return new RetypedClosure(closure, types as Class[])

Then we define our new method like this:

def pointClass = Class.forName("Point")
DataOutputStream.metaClass.write << retype([pointClass]) {
    final point ->

How it works:

The RetypedClosure class is a wrapper class. It inherits from the Closure class and overrides the Closure.getParameterTypes method to express the desired types for Groovy to understand. The RetypedClosure.doCall method is also added because Groovy needs it to allow Groovy code to call our retyped closure with the function/method call syntax. The retype function then accepts our untyped closure and wraps it in another retyped closure that provides the necessary type information.

Many thanks to Luke Daley for his suggestion on overriding the Closure class and Paulo Gabriel Poiati and others on the Groovy users mailing list for sharing their ideas.

This entry was posted in groovy, software development. Bookmark the permalink.

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 )

Google+ photo

You are commenting using your Google+ 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 )

Connecting to %s