Skip to content
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 · 3 comments · Fixed by #1342
Closed

Using httptest #719

athoune opened this issue Oct 28, 2016 · 3 comments · Fixed by #1342
Labels

Comments

@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
Copy link
Member

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?

@hadrienk
Copy link

Sorry for reopening old issues but I think testing parameter validation/binding is quite important as well. Is there an easy way to do so?

@casualjim
Copy link
Member

yes you can construct the parameters struct and test the validation cases

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants