Groovy HttpBuilder - Get Body Of Failed Response

后端 未结 3 857
后悔当初
后悔当初 2021-02-05 16:52

I am trying to use the Groovy HTTPBuilder to write an integration test that will verify a correct error message is returned in the body along with an HTTP 409 status message. Ho

相关标签:
3条回答
  • 2021-02-05 17:00

    I was recently just struggling with this while trying to integration test my REST endpoints using Spock. I used Sam's answer as inspiration and ended up improving on it so as to continue leveraging the auto-casting that HttpBuilder provides. After messing around for a while, I had the bright idea of just assigning the success handler closure to the failure handler to standardize the behavior regardless of what status code is returned.

    client.handler.failure = client.handler.success
    

    An example of it in action:

    ...
    
    import static org.apache.http.HttpStatus.*
    
    ...
    
    private RESTClient createClient(String username = null, String password = null) {
        def client = new RESTClient(BASE_URL)
        client.handler.failure = client.handler.success
    
        if(username != null)
            client.auth.basic(username, password)
    
        return client
    }
    
    ...
    
    def unauthenticatedClient = createClient()
    def userClient = createClient(USER_USERNAME, USER_PASSWORD)
    def adminClient = createClient(ADMIN_USERNAME, ADMIN_PASSWORD)
    
    ...
    
    def 'get account'() {
        expect:
        // unauthenticated tries to get user's account
        unauthenticatedClient.get([path: "account/$USER_EMAIL"]).status == SC_UNAUTHENTICATED
    
        // user gets user's account
        with(userClient.get([path: "account/$USER_EMAIL"])) {
            status == SC_OK
            with(responseData) {
                email == USER_EMAIL
                ...
            }
        }
    
        // user tries to get user2's account
        with(userClient.get([path: "account/$USER2_EMAIL"])) {
            status == SC_FORBIDDEN
            with(responseData) {
                message.contains(USER_EMAIL)
                message.contains(USER2_EMAIL)
                ...
            }
        }
    
        // admin to get user's account
        with(adminClient.get([path: "account/$USER_EMAIL"])) {
            status == SC_OK
            with(responseData) {
                email == USER_EMAIL
                ...
            }
        }
    }
    
    0 讨论(0)
  • 2021-02-05 17:16

    I also struggled with this when I started using HttpBuilder. The solution I came up with was to define the HTTPBuilder success and failure closures to return consistent values like this:

    HTTPBuilder http = new HTTPBuilder()
    http.handler.failure = { resp, reader ->
        [response:resp, reader:reader]
    }
    http.handler.success = { resp, reader ->
        [response:resp, reader:reader]
    }
    

    Thusly defined, your HTTPBuilder instance will consistently return a map containing a response object (an instance of HttpResponseDecorator) and a reader object. Your request would then look like this:

    def map = http.request(ENV_URL, Method.POST, ContentType.TEXT) {
        uri.path = "/curate/${id}/submit"
        contentType = ContentType.JSON
    }
    
    def response = map['response']
    def reader = map['reader']
    
    assert response.status == 409
    

    The reader will be some kind of object that'll give you access to the response body, the type of which you can determine by calling the getClass() method:

    println "reader type: ${reader.getClass()}"
    

    The reader object's type will be determined by the Content-Type header in the response. You can tell the server specifically what you'd like returned by adding an "Accept" header to the request.

    0 讨论(0)
  • 2021-02-05 17:17

    Does it work if you use:

    response.failure = { resp, reader ->
        failstatus = resp.statusLine
        failresp   = reader.text
    }
    
    0 讨论(0)
提交回复
热议问题