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

How to test my handlers with middleware #659

Closed
heynemann opened this issue Sep 12, 2016 · 6 comments
Closed

How to test my handlers with middleware #659

heynemann opened this issue Sep 12, 2016 · 6 comments
Assignees
Labels

Comments

@heynemann
Copy link

Description

Sorry for all the questions, but I'm very new to Echo. Right now I'm writing a test that validates my handler.

The test is passing, but it does not invoke middleware. This is an issue in my scenario because my middleware authenticates that user and store the user in the context.

I'm using the way described in the docs. I've also tried using httptest.NewServer, but echo is not a valid http.Handler (ServeHTTP has wrong type of arguments).

Any ideas on how to do this?

@heynemann
Copy link
Author

If anyone wants to do this I figured it out:

//Get from server
func Get(app *api.App, url string) (int, string) {
    return doRequest(app, "GET", url, auth)
}

func doRequest(app *api.App, method, url string) (int, string) {
    app.Engine.SetHandler(app.Echo)
    ts := httptest.NewServer(app.Engine.(*standard.Server))
    defer ts.Close()

    req, err := http.NewRequest("GET", fmt.Sprintf("%s%s", ts.URL, url), nil)
    gomega.Expect(err).NotTo(gomega.HaveOccurred())

    client := &http.Client{}
    res, err := client.Do(req)
    gomega.Expect(err).NotTo(gomega.HaveOccurred())

    if res != nil {
        defer res.Body.Close()
    }

    b, err := ioutil.ReadAll(res.Body)
    gomega.Expect(err).NotTo(gomega.HaveOccurred())

    return res.StatusCode, string(b)
}

App is a struct I have that has both the Engine I'm running Echo on, as well as the Echo struct.

It's worth noting that this approach only works if you are using the standard engine. But IMHO it's good enough for tests.

Using it is as simple as:

status, body := Get(app, "/experiments", "test@test.com")
Expect(status).To(Equal(http.StatusOK))
Expect(body).NotTo(BeEmpty())

I simplified the assertions just to show how it's used. Ideally you would assert the contents of the body (JSON in my scenario).

As this can be easily accomplished I'm closing this issue. I do believe that having a stronger testing infrastructure would benefit echo, though.

@vishr vishr self-assigned this Sep 13, 2016
@vishr vishr added the question label Sep 13, 2016
@AA33
Copy link

AA33 commented Nov 8, 2016

@heynemann where do you add your middleware? Is it already added to the Echo struct before you use it in doRequest?
I'm facing a similar problem with my middleware that wraps request handling in a DB transaction.

@heynemann
Copy link
Author

I add my engine to echo.Echo. Not sure what you mean, but you can see it in use in my repo at https://github.com/topfreegames/khan

Hope it helps!

@savely-krasovsky
Copy link

savely-krasovsky commented Jul 18, 2018

@heynemann sorry for necroposting, but I found more correct way, I guess:

func TestReset(t *testing.T) {
	// Setup
	e := echo.New()

	req := httptest.NewRequest(echo.POST, v1+"/reset", nil)
	req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
	req.Header.Set(echo.HeaderAuthorization, defaultUUID)

	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)
	
	// Middlewares chaining (it goes from inside to outside
	c.SetHandler(
		ContextExtender(testDB, testConfig)(
			Authorization(
				// Your method here
				Reset,
			),
		),
	)

	// Here you call it and test, magic!
	if assert.NoError(t, c.Handler()(c)) {
		assert.Equal(t, http.StatusOK, rec.Code)
	}
}

Hope my example will help others.

@jwendel
Copy link

jwendel commented Nov 8, 2018

As I stumbled about this on how to test middleware, here's an example of using echo.ServerHTTP, which will end up triggering the router logic along with all middleware you have setup.

sample.go

package sample

import (
	"net/http"
	"github.com/labstack/echo"
)

func ServerHeader(next echo.HandlerFunc) echo.HandlerFunc {
	return func(c echo.Context) error {
		c.Response().Header().Set(echo.HeaderServer, "Echo/3.0")
		return next(c)
	}
}

func initEcho() *echo.Echo {
	e := echo.New()
	e.Use(ServerHeader)
	e.GET("/", rootUrl)
	return e
}

func rootUrl(c echo.Context) error {
	return c.HTML(http.StatusOK, "body output")
}

sample_test.go

package sample

import (
	"net/http"
	"net/http/httptest"
	"testing"
	"github.com/labstack/echo"
	"github.com/stretchr/testify/assert"
)

func TestMiddleware(t *testing.T) {
	e := initEcho()
	req := httptest.NewRequest(echo.GET, "/", nil)
	rec := httptest.NewRecorder()
	// Using the ServerHTTP on echo will trigger the router and middleware
	e.ServeHTTP(rec, req)

	assert.Equal(t, http.StatusOK, rec.Code)
	assert.Equal(t, rec.Body.String(), "body output")
	assert.Equal(t, rec.Header().Get(echo.HeaderServer), "Echo/3.0")
}

@kitamura-tetsuo
Copy link

@jwendel thx. beautiful code. expected and actual were swapped in assert.Equal.

sample_test.go

func TestMiddleware(t *testing.T) {
...
	assert.Equal(t, rec.Body.String(), "body output")
	assert.Equal(t, rec.Header().Get(echo.HeaderServer), "Echo/3.0")
func TestMiddleware(t *testing.T) {
...
	assert.Equal(t, "body output", rec.Body.String())
	assert.Equal(t, "Echo/3.0", rec.Header().Get(echo.HeaderServer))

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

No branches or pull requests

6 participants