Groovy on Grails and my “Test First” impasse

I’ve hit what would be a test first impasse (if I had tried to write my test first). So in an attempt to leave it alone, I’ll record where I got to and the resources that I think nearly got me to a solution…

I have a domain object for which I want to return a filtered set. I know that this can be done as a closure to the list method of hibernate criteria and having figured out how to mock a closure I can assert that a filter has indeed been applied.

def criteria = Customer.createCriteria() 
items = criteria.list(params) { 
  or { 
    ilike ('surname', "%${params.filter}%") 
    ilike ('forename', "%${params.filter}%") 
    ilike ('emailAddress', "%${params.filter}%") 
  } 
} 
--- 
def customerCriteria = new MockFor(org.hibernate.Criteria) 
customerCriteria.demand.list { 
  Map params, 
  Closure cls -> testItems 
} 
Customer.metaClass.static.createCriteria = { org.hibernate.Criteria }

But how can I assert that the filter closure contains/does what I want?

Having mocked the closure call, I now want to define what it is supposed to do in my unit test.

I just can’t figure out how and I have started delving much deeper into how closures work than I originally wanted to. Unfortunately, I don’t seem to get any further than the MetaClass, where everything is still a little abstract. There must be some representation of the code to be run/resolved in there somewhere!?

I’ve poured over the hierarchy for package groovy.lang and pages on Closures and the ExpandoMetaClass - GroovyObject Methods.

Kick started by Fun with Groovy and the Reflection API and definitely helped by What methods does my Groovy/Grails class have? I distilled my problem to a script and proceeded to dump anything and everything I could think of or come across…

class MyClassUnderTest { 
  def foo() { return "foo" } 
  def bar() { return "bar" } 
  def ray() { return "ray" } 
  def someMethod(Closure val) { 
    println("Closure:") 
    println(val.dump()) 
    println("-----------------------------------------------------------------") 
    println("My Closure: ") 
    println(val.getMyClosure().dump()) 
    println("-----------------------------------------------------------------") 
    println("Meta Class: ") 
    println(val.getMyClosure().metaClass.dump()) 
    println("-----------------------------------------------------------------") 
    println("My Meta Class: ") 
    println(val.getMyClosure().metaClass.myMetaClass.dump()) 
    println("-----------------------------------------------------------------") 
    println("My Meta Class Methods Index: ") 
    println(val.getMyClosure().metaClass.myMetaClass.metaMethodIndex.table*.name.sort().unique() ) 
    println("-----------------------------------------------------------------") 
    println(val.getMyClosure().metaClass.inheritedMetaMethods*.name.sort().unique()) 
    println(val.getMyClosure().metaClass.methods*.name.sort().unique()) 
    println("-----------------------------------------------------------------") 
    println(val.getMyClosure().metaClass.theClass.dump()) 
    println("-----------------------------------------------------------------") 
    println("Constructors:") val.getMyClosure().metaClass.theClass.declaredConstructors.each { 
      println it.toGenericString() 
    } 
    println("-----------------------------------------------------------------") 
    println("Methods:") val.getMyClosure().metaClass.theClass.declaredMethods.each { 
        println it.toGenericString() 
    } 
    println("-----------------------------------------------------------------") 
    return 'result!' 
  } 
} 
def cut = new MyClassUnderTest() 
def myClosure = { 
  foo ('valueOne') 
  bar ('valueTwo') 
  ray ('valueThree') 
  'valueFour' 
} 
cut.someMethod { myClosure }

I thought I might have struck lucky when came across a post by Danno Ferrin who had learned more than he wanted to know about groovy.lang.Closure. This cleared up a great deal about scope and lead me to a post by Guillaume Laforge on knowing which variables are bound or not in a Groovy script.

Unfortunately the actual contents of the closure still allude me, but I’ve got work to do and this has had far more of my time than I can justify!

comments powered by Disqus