API Endpoint Testing With Groovy & Spock

best endpoint test frameworkThere are several ways of making http requests through java and groovy. You can use anything from Netflix’s feign client┬áto standard http url connection classes built into java. I have used many different classes/frameworks for testing system integrations. My favorite choice by far is to use either groovy’s http builder or another class that extends it called RESTClient. Typically I build a wrapper class that logs into the service and stores server authentication credentials. This wrapper class works best as a singleton or using dependency injection to keep only once instance of the class available for use throughout the test suite. The reason I love groovy’s restclient is because it is so easy to make the standard http requests for any different type of endpoint. You can then make objects that represent the basic crud operations to wrap your api’s endpoints. Next you make a bunch of Spock specifications making great endpoint testing specs.

Wrapping the RESTClient

The following is just an example of wrapping the rest client into a singleton. When the object gets initialized you can log into your api. Making this a singleton is great because you can just store the authentication credentials and every request you make doesn’t need to reauthenticate. If you ever need to store various user roles you can just store the authentication keys in the singleton too.

package util

import groovyx.net.http.HttpResponseDecorator
import groovyx.net.http.RESTClient
import spock.lang.Shared

/**
 * Created by derekcarr on 5/14/15.
 */
@Singleton(strict = false, lazy = true)
class RESTClientHelper {

    protected RESTClient rc
    @Shared def authResp
    @Shared def userName = "user.name"
    def host = System.getProperty("test.host","www.domain.com")
    
    //This is to initialize your rest client with the authentication you need
    private RESTClientHelper(){
        authenticationSID = login(host)
    }

    public synchronized HttpResponseDecorator delete(Map vals) {
        addHeaders(vals)
        return rc.delete(vals)
    }

    public synchronized HttpResponseDecorator get(Map vals) {
        addHeaders(vals)
        return rc.get(vals)
    }

    public synchronized HttpResponseDecorator put(Map vals) {
        addHeaders(vals)
        return rc.put(vals)
    }

    public synchronized HttpResponseDecorator post(Map vals) {
        addHeaders(vals)
        return rc.post(vals)
    }

    void dump(HttpResponseDecorator resp) {
        println 'Header/Status\n--------------------------------'
        println 'Status: '+resp.status
        println 'Content Type: '+resp.contentType
        println 'Headers:'+resp.allHeaders
        println '\nBody\n--------------------------------'
        println JsonOutput.prettyPrint(JsonOutput.toJson(resp.data))
    }

    private addHeaders(Map vals) {
        if (vals.containsKey("headers"))
            rc.headers += vals
    }

    def login = { host ->
        //Login and get a SID
        def u = "qa14.tester@domain.com"
        def p = "p@ssw0rd"
        def resp = new RESTClient("https://${host}").post(
                path: '/api/domain/auth/login',
                body: [username: u, password: p],
                requestContentType: ContentType.JSON
        )
        return URLDecoder.decode(resp.responseData.sid.toString(), "UTF-8")
    }

}

Comments are closed.