englishteeth.co.uk

… the weblog of Ian “English Teeth” Robinson
  • rss
  • Home

Grails Unit Testing: How to mock a closure

Ian | August 29, 2008

I have found numerous resources on testing in grails, unit testing and Using MockFor and StubFor in groovy. However, given that closures are one of the key features of groovy, I found very little on how to accommodate them in testing.

The following is a simple controller with a list action that returns a set of Customer domain objects from a database and this action applies some simple filter criteria (thanks to this post I came across):

   def list = {
        def items

        if(!params.max) params.max = 10
        if(!params.sort) params.sort = "lastUpdated"
        if(!params.order) params.order= "desc"
        if (params?.filter) {
            def criteria = Customer.createCriteria()
            items = criteria.list(params) {
                or {
                        ilike ('surname', "%${params.filter}%")
                        ilike ('forename', "%${params.filter}%")
                        ilike ('emailAddress', "%${params.filter}%")
                }
            }
        }
        else {
            items = Customer.list (params)
        }

        render (view: 'list', model: [ customerList: items, filter:params.filter ], params: params)
    }

This action uses the Hibernate Criteria Builder to construct the query.

When unit testing Grails does not inject any of the dynamic methods and so these must be provided for. For this I covered the dynamic controller methods in the set up and tear down operations (thanks wholly to Glen Smith’s MockFor(March): Unit Testing Grails Controllers…

    def redirectParams
    def renderParams
    def params

    /** Setup metaclass fixtures for mocking. */
    void setUp() {

        params = [ : ]
        CustomerController.metaClass.getParams = { -> params }

        redirectParams = [ : ]
        CustomerController.metaClass.redirect = { Map args -> redirectParams = args  }

        renderParams= [ : ]
        CustomerController.metaClass.render = { Map args -> renderParams = args  }

    } 

    /** Remove metaclass fixtures for mocking. */
    void tearDown() {
        def remove = GroovySystem.metaClassRegistry.&removeMetaClass
        remove CustomerController
    }

The dynamic methods for the domain class I covered in the test where they were used.

    void testNoFilterReturnsList() {

        def testItems = [ 'x', 'y', 'z' ]

        params['filter'] = null ;

        // mock the static list and count methods
        Customer.metaClass.static.list = { Map params -> testItems } 

        CustomerController cc = new CustomerController()
        cc.list()

        assertNull renderParams.model.filter
        assertEquals testItems, renderParams.model.customerList

    }

This could hardly be simpler and is covered in much more detail elsewhere. Where I ran into difficulty was testing the the criteria was applied.

I wanted to provide a mock object for the org.hibernate.Criteria object returned for the domain.
def customerCriteria = new MockFor(org.hibernate.Criteria)
Defining expectations on the mock object is straight forward too, just demand it!
customerCriteria.demand.list { -> testItems }
Except that what ever I seemed to try would not match the signature of the call to list that I was trying to do in the filter test above.

Despite being a little elusive, the answer was simple enough. The closure defining the search criteria is a parameter to the call. There must be a list method declared with a signature along the lines of
def list (Map params, Closure criteria)(At least, that’s what I had to do in a test class to mimic that results I was seeing.)

So, to define a demand to match that… well, just treat it as such.

    void testFilterAppliedToCriteria() {

        def testItems = [ 'x', 'y', 'z' ]

        params['filter'] = 'search on something' ;

        def customerCriteria = new MockFor(org.hibernate.Criteria)
        customerCriteria.demand.list { Map params, Closure cls -> testItems }
        Customer.metaClass.static.createCriteria = { org.hibernate.Criteria }
        customerCriteria.use{
        	CustomerController cc = new CustomerController()
        	cc.list()

        	assertEquals params.filter, renderParams.model.filter
        	assertEquals testItems, renderParams.model.customerList
        }
    }

I continue to stumble through, though I’m becoming more convinced that I don’t know what I am doing.

Comments
4 Comments »
Categories
development
Tags
closures, grails, groovy, hibernate, testing
Comments rss Comments rss
Trackback Trackback

Author

Ian Robinson is a relatively agile software engineer interested in things both sides of the object relational divide and beyond.

Categories

  • development (37)
  • miscellaneous (28)
  • music (7)
  • software (19)

What I'm Doing...

  • @noelfielding11 why are you in watching telly!? in reply to noelfielding11 2010-04-16
  • What was so good about Nick Drake? These "artists" are covering, music is spot on but no effect at all. Totally lacking the goose pimples. 2010-04-16
  • Some Ginger bloke's on telly covering Nick Drake in a mediocre style. 2010-04-16
  • More updates...

Posting tweet...

Powered by Twitter Tools.

Blogroll

  • Dan North
  • Dave Astels
  • Dave Wood
  • eirikso.com
  • Matt Raible
  • Object Mentor Blog
  • The Ancient Art of Programming
  • The Wisdom of Ganesh

Tags

active-mq architecture bauhaus css db eclipse esb festivals freesat gorm grails groovy hd hibernate htpc java jboss jms junit links mce media center mini music oracle osgi patterns pirsig plugins satellite soa software spring sql struts2 testing themes tools tv vmc web wordpress xml xpath xslt
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox