New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using httptest #719

Closed
athoune opened this Issue Oct 28, 2016 · 1 comment

Comments

Projects
None yet
2 participants
@athoune
Copy link

athoune commented Oct 28, 2016

I would like to use httptest for testing my handlers.

Go-swagger provides a Server, but not a configured handler. I use this hack : in a file test.go in the restapi folder, I steal the private configureAPI function. It works.

package restapi

import (
    loads "github.com/go-openapi/loads"
    "github.com/pim/pam/poum/restapi/operations"
    "net/http"
)

func getAPI() (*operations.ThefactoryAPI, error) {
    swaggerSpec, err := loads.Analyzed(SwaggerJSON, "")
    if err != nil {
        return nil, err
    }
    api := operations.NewThefactoryAPI(swaggerSpec)
    return api, nil
}

func GetAPIHandler() (http.Handler, error) {
    api, err := getAPI()
    if err != nil {
        return nil, err
    }
    h := configureAPI(api)
    err = api.Validate()
    if err != nil {
        return nil, err
    }
    return h, nil
}

I can use is in test like this

    handler, err := restapi.GetAPIHandler()
    if err != nil {
        t.Fatal("get api handler", err)
    }
    ts := httptest.NewServer(handler)
    defer ts.Close()
    res, err := http.Get(ts.URL + "/api/v1/boxes")

But, hacking restapi, wich use my handlers is cyclic, I can't drop my test near my handlers, and this is still a hack.

What is the offical way to manage handler testing?

@casualjim casualjim added the question label Oct 28, 2016

@casualjim

This comment has been minimized.

Copy link
Member

casualjim commented Oct 28, 2016

You don't actually need httptest to test the handlers.
A handler is essentially a function of parameters to result.
The result knows how to write itself to a http.ResponseWriter, and you already know that that part works.
So to test a handler what you require is to test just your code.

So to test the AddOne operation from the todo list this, there are 2 functions involved in the implementation.

The first function uses the data from the request to actually write the todo item to a store, this can be tested separately.

func addItem(item *models.Item) error {
    if item == nil {
        return errors.New(500, "item must be present")
    }

    itemsLock.Lock()
    defer itemsLock.Unlock()

    newID := newItemID()
    item.ID = newID
    items[newID] = item

    return nil
}

Then there is the actual handler:

todos.AddOneHandlerFunc(func(params todos.AddOneParams) middleware.Responder {
  if err := addItem(params.Body); err != nil {
    return todos.NewAddOneDefault(500).WithPayload(&models.Error{Code: 500, Message: swag.String(err.Error())})
  }
  return todos.NewAddOneCreated().WithPayload(params.Body)
})

To test this second function we don't need to use the httptest package, you can assume that that part of the code works. So all you have to test is whether or not you get the right return types for a given set of parameters.

Do you think this is sufficient?

@fredbi fredbi referenced this issue Dec 23, 2017

Merged

A FAQ md to recap questions #1342

4 of 4 tasks complete

@fredbi fredbi closed this in #1342 Dec 23, 2017

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment