Mocking Log Service and Others in Grails and Groovy

In this post, we cover different ways of mocking Services and other entities when writing tests in Grails. For the examples in this post, we use the Log service to better demonstrate

Environment: Grails 2.1.2, Spock 1.0, Mac 10.7

Using Grails mockFor

In this example, the Grails mockFor mechanism of mocking is used to mock the log service:


    def "mock using grails mockFor"(){
        setup:
        def httpBuildMock = new MockFor(HTTPBuilder.class)
        def logTo = []
        def loggerMock = mockFor(org.apache.commons.logging.Log)
        loggerMock.demand.warn(1..1){ String message ->
            logTo << [msg:message,level: 'warn']
        }
        service.log = loggerMock.createMock()

        when:
        service.methodLogging()

        then:
        assert logTo.msg == 'some message'

First we create global variable ‘logTo’ to store the logged value, so we can assert it later. Then we create mock of Log interface and mock the method ‘log.warn’. At last, the mocked logger is assigned to the logger used by the service

Using Groovy Closure

Since Groovy provides convenient way to implement interfaces, the mocking of logger can be done via closure as following:

def "mock via groovy closure"(){
        setup:
        def logTo = []
        def logInstance = {String message -> logTo << [msg: message]} as org.apache.commons.logging.Log
        service.log = logInstance

        when:
        service.methodLogging()

        then:
        assert logTo.msg == 'some message'

In the highlight line, the closure is created and assigned to a type of org.apache.commons.logging.Log interface. This closure is going to be executed whenever any of the Log methods(warn,error,etc.) is going to be called. Afterwards, the new logger is assigned to the service logger instance

Important to note, for mocking multiple methods the interface is implemented via Groovy Map as following

def "mock via groovy closure"(){
        setup:
        def logTo = []
        def impl = [
                warn:{String message ->
                    logTo << [warn: message]
                },
                error:{String message ->
                    logTo << [error: message]
                }
        ]

        def logInstance = impl as org.apache.commons.logging.Log
        service.log = logInstance

        when:
        service.methodLogging()

        then:
        assert logTo.warn == 'some message'
        assert logTo.error == 'some message'

As you see, here the two closures one for method ‘warn’ and another for ‘error’ are created and put into Map. Afterwards, the interface type assigned and injected into service as the logger instance

Using Groovy MockFor

Another alternative is to use Groovy MockFor mechanism that is very similar to the one in Grails

def "mock via groovy MockFor"(){
        setup:
        def logTo = []
        def logService = new MockFor(org.apache.commons.logging.Log)
        logService.demand.warn(1){ String message ->
            logTo << [msg: message]
        }
        service.log = logService.proxyInstance()

        when:
        service.methodLogging()

        then:
        assert logTo.warn == 'some message'

This is almost identical to Grails mockFor implementation

In summary, there are choices when mocking logger or any other collaborator for that matter. The three different alternatives listed here can be applied to any collaborator in your test of interest

Useful links:

  • http://slf4j.org/faq.html about IlligalAccessError
  • http://blog.springsource.com/2009/12/04/logging-dependencies-in-spring/
  • http://stackoverflow.com/questions/3032654/hibernate-spring-and-slf4j-binding
  • http://groovy.codehaus.org/Groovy+way+to+implement+interfaces

Leave a Reply

Your email address will not be published. Required fields are marked *