2

I'm trying to test a handler in Go using Echo. Here is the handler:

func submitted(c echo.Context) error {
    // do stuff with JSON here
    return c.Render(http.StatusOK, "submitted", "true")
}

and the test:

import (
    "testing"
    "net/http/httptest"
    "net/http"
    "github.com/labstack/echo"
    "strings"
    "fmt"
    "html/template"
)

var userJSON = `{<values go here>}`

func TestFunction(t *testing.T) {
    te := &Template{
        templates: template.Must(template.ParseGlob("public/views/*.html")),
    }
    e := echo.New()
    e.Renderer = te
    req := httptest.NewRequest(http.MethodPost, "/submitted", strings.NewReader(userJSON))
    req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
    rec := httptest.NewRecorder()
    c := e.NewContext(req, rec)
    fmt.Println(rec.Body.String())
}

However, no body is returned it seems - even though the handler returns submitted.html file when running regularly. Any ideas?

flowermia
  • 389
  • 3
  • 17

1 Answers1

0

There is one element which seems missing from your test function: a handler.

Compare your approach to "Build a web application in Go (golang) / Testing" from Soham Kamani:

//main_test.go

package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestHandler(t *testing.T) {
    //Here, we form a new HTTP request. This is the request that's going to be
    // passed to our handler.
    // The first argument is the method, the second argument is the route (which
    //we leave blank for now, and will get back to soon), and the third is the
    //request body, which we don't have in this case.
    req, err := http.NewRequest("GET", "", nil)

    // In case there is an error in forming the request, we fail and stop the test
    if err != nil {
        t.Fatal(err)
    }

    // We use Go's httptest library to create an http recorder. This recorder
    // will act as the target of our http request
    // (you can think of it as a mini-browser, which will accept the result of
    // the http request that we make)
    recorder := httptest.NewRecorder()

    // Create an HTTP handler from our handler function. "handler" is the handler
    // function defined in our main.go file that we want to test
    hf := http.HandlerFunc(handler)

    // Serve the HTTP request to our recorder. This is the line that actually
    // executes our the handler that we want to test
    hf.ServeHTTP(recorder, req)

    // Check the status code is what we expect.
    if status := recorder.Code; status != http.StatusOK {
        t.Errorf("handler returned wrong status code: got %v want %v",
            status, http.StatusOK)
    }

    // Check the response body is what we expect.
    expected := `Hello World!`
    actual := recorder.Body.String()
    if actual != expected {
        t.Errorf("handler returned unexpected body: got %v want %v", actual, expected)
    }
}
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Thank you - this helps a little, although since I'm using Echo I'm not entirely sure how to write the handler call. I get this error: cannot convert submitted (type func(echo.Context) error) to type http.HandlerFunc, which makes sense. – flowermia May 24 '21 at 07:29
  • @flowermia You need an http handler wrapper: https://medium.com/@matryer/the-http-handler-wrapper-technique-in-golang-updated-bc7fbcffa702. That will accommodate any function signature. – VonC May 24 '21 at 07:30
  • Still can't seem to work this out, would you be able to provide an example of a wrapper with my current handler? – flowermia May 24 '21 at 08:38
  • This example doesn't seem to have a handler and works okay: https://stackoverflow.com/questions/53163520/testing-post-request-with-echo-expected-vs-actual-output – flowermia May 24 '21 at 08:57
  • @flowermia that one actually does call a handler, `if assert.NoError(t, newHouse(c)) {` - here `newHouse` is the OP's handler that is being tested – Rafat Rashid Jul 25 '21 at 09:41