Mock HTTPBuilder and POST requests in Grails

For some reason, mocking HTTPBuilder become a larger task than initially anticipated. In this post, the details on how to assert params, payload of the HTTPBuilder request as well as success or failure of the response is covered to have a good test

Here is an example of the HTTP POST request:

class NodeDriverProxyService {
   def http = new HTTPBuilder('http://localhost:8080')

    public registerUpdate(Long id, Long version){
        try{
            http.request(Method.POST, JSON){ req ->
                body = [
                        version: version,
                        id: id
                ]

                response.success = {resp, json ->
                    log.warn "cached object id: $id and version: $version; status code: " + resp.statusLine.statusCode
                }
            }
        }catch(Exception e){
            log.warn('Failure Initiate Connection with Node Driver: ' + e.message);
        }
    }
}

Here the httpBuild is initiated in line 2. The request takes ‘id’ and ‘version’. On the response, the message is logged with the response status(line 13). The error message is also logged if exception encountered at any time during request

1. Test Params

Here is the test for ensuring params(method, body, etc.) passed in the request accordingly

@Shared  id = 2, ver = 3
def "ensure params passed in correctly"(){
        setup:
        def httpBuildMock = new MockFor(HTTPBuilder.class)
        def reqPar = []
        def success

        def requestDelegate = [
                response: [:]
        ]

        httpBuildMock.demand.request(1){
            Method met, ContentType type, Closure b ->
            b.delegate = requestDelegate
            b.call()
            reqPar << [method: met, type: type, id: b.body.id, ver: b.body.version ]
        }

        when:
        httpBuildMock.use{
            service.registerUpdate(id,ver)
        }

        then:
        assert reqPar[0].method == Method.POST
        assert reqPar[0].type == ContentType.JSON
        assert reqPar.ver[0] == ver
        assert reqPar.id[0] == id
    }

First, we declare a list – reqPar(line 5) to hold all of the params since its accessible only within the request scope and we prefer to do assertions outside the request scope part of the ‘then’ block(line 23 – 27)

Next, we mock interface(line 8-10) of the RequestConfigDelegate class because it is the owner scope calling the request method. We also assign it in line 13 to the ‘request’ closure before executing it in next line

We need to execute the ‘request’ closure in line 15, because within that scope the body params are assigned, thus, available for us to access that we are doing in line 15. Beside body params, there may also uri.path, uri.query but in our implementation there isn’t.

2. Test Response

Our other test is going to be testing the successful and failure response.

@Shared  id = 2, ver = 3, status_code = 200, msg = 'test message'
 def "ensure response is handled accordingly for success and failure states"(){

        setup:
        def logTo = []
        def success
        def httpBuildMock = new MockFor(HTTPBuilder.class)

        def logService = [
                warn: { String message ->
                    logTo << [warn: message]
                }         
             ] as org.apache.commons.logging.Log
       
        def requestDelegate = [
                            response: [ 
                                 'statusLine': [ 'protocol': 'HTTP/1.1',
                                                 'statusCode': status_code, 
                                                 'status':'OK'
                                               ]
                                 ],
        ]
      
        httpBuildMock.demand.request(1){Method met, ContentType type, Closure b ->
            b.delegate = requestDelegate
            b.call()
            if(success) {
                requestDelegate.response.success(requestDelegate.response,[:])
            }else{
                throw new Exception(msg)
            }
        }
        service.log = logService

        httpBuildMock.use{
            success = state
            service.registerUpdate(id,ver)
        }

        expect:
        assert logTo[0].warn == message

        where:
        state   | message
        false   | 'Failure Initiate Connection with Node Driver: ' + msg
        true    | 'cached object id: ' + id + ' and version: ' + ver + '; status code: ' + status_code

    }

In our case, in both situation for successful and failure response there are messages logged, so we mock the log service as well in the lines 8-12.

Besides mocking the Log service and asserting the messages, we initiate the response in the highlighted line as it would be when our Http POST request would receive the response. For response, the same RequestConfigDelegate interface is also passed into as response, however. We add ‘statusLine’ in this mocked requestConfigDelegate instance since the ‘statusLine’ is being called and we also need it for the assertion in the ‘where’ block

Useful Links:

  • http://cscarioni.blogspot.com/2011/02/is-it-harder-to-unit-test-in-grails.html
  • http://groovy.codehaus.org/Developer+Testing+using+Closures+instead+of+Mocks
  • http://groovy.codehaus.org/Groovy+way+to+implement+interfaces
  • http://stackoverflow.com/questions/13790246/how-to-use-mockfor-to-mock-client-on-httpbuilder
  • http://groovyconsole.appspot.com/script/760001
  • http://jira.grails.org/browse/GRAILS-8617
  • http://groovy.codehaus.org/modules/http-builder/apidocs/groovyx/net/http/HTTPBuilder.html#request(groovyx.net.http.Method, groovy.lang.Closure)

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

Spock with Grails

In this post, i hope to cover installing, configuring and using Spock testing framework with Grails. Spock is a testing and specification framework for Java and Groovy applications.

Environment at the writing: jdk1.7.0_07, Grails 2.1.1

1. Installing & Configuring Spock Plugin

One Way – Configure Spock by adding following line in \grails-app\conf\BuildConfig.groovy:

At compile time, Grails will detect that you have configured Spock and install the plugin

Second Way – Run command ‘grails install-plugin spock’ from command line and it will install&configure the Spock for you

To verify at any time, open the dependency report by calling command ‘grails dependency-report” or ‘open dep-report’ from interactive grails console. The report will look like the following:

From the report, look at the  ‘test’ tab to see the ‘Spock’ Plugin

2. Implementing

For Unit Tests – extend your Test class with ‘UnitSpec’ and import the library as following:

For Integration Tests – extend your Test class with ‘IntegrationSpec’ and import the library as following:

4. Running Tests

To Run Unit Tests – one way is to call command ‘grails test-app unit:spock <nameOfTestClass>.<nameOfTest>’ . The other way is depending on your IDE  (IntellJ right click from test itself->Run)

To Run Integration Tests – one way is to call command ‘grails test-app integration:spock <nameOfTestClass>.<nameOfTest>’. The other way is depending on your IDE (IntellJ right click from test itself ->Run)

5. Other

Sharing or Reusing – Spock allows an easy way to reuse or share an object among the individual tests(method features) as following:

Its accomplished by adding notation ‘@Shared’ when declaring the object. Also, don’t forget to import ‘spock.lang.Shared’ package

Sources:

 

Issues Encountered:

1. “Cannot get property ‘autowireCapableBeanFactory’ on null object”. We were getting these because for Integration test we cannot use Unit test mixines, so by dropping @TestFor(class) and @TestMixin(GrailsUnitTestMixin) it solved the problem