Testing
Testing Handler
GET /users/:id
Handler below retrieves user by id from the database. If user is not found it returns
404 error with a message.
CreateUser
POST /users
- Accepts JSON payload
- On success
201 - Created - On error
500 - Internal Server Error
GetUser
GET /users/:email
- On success
200 - OK - On error
404 - Not Foundif user is not found otherwise500 - Internal Server Error
handler.go
package handler
import(
"net/http"
"github.com/labstack/echo/v5"
)
type(
User struct{
Name string`json:"name" form:"name"`
Email string`json:"email" form:"email"`
}
handler struct{
db map[string]*User
}
)
func(h *handler)createUser(c *echo.Context)error{
u :=new(User)
if err := c.Bind(u); err !=nil{
return err
}
return c.JSON(http.StatusCreated, u)
}
func(h *handler)getUser(c *echo.Context)error{
email := c.Param("email")
user := h.db[email]
if user ==nil{
return echo.NewHTTPError(http.StatusNotFound,"user not found")
}
return c.JSON(http.StatusOK, user)
}
handler_test.go
package handler
import(
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/labstack/echo/v5"
"github.com/labstack/echo/v5/echotest"
"github.com/stretchr/testify/assert"
)
var(
mockDB =map[string]*User{
"[email protected]":&User{"Jon Snow","[email protected]"},
}
userJSON =`{"name":"Jon Snow","email":"[email protected]"}`
)
funcTestCreateUser(t *testing.T){
// Setup
e := echo.New()
req := httptest.NewRequest(http.MethodPost,"/", strings.NewReader(userJSON))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
h :=&controller{mockDB}
// Assertions
if assert.NoError(t, h.createUser(c)){
assert.Equal(t, http.StatusCreated, rec.Code)
assert.Equal(t, userJSON, rec.Body.String())
}
}
// Same test as above but using `echotest` package helpers
funcTestCreateUserWithEchoTest(t *testing.T){
c, rec := echotest.ContextConfig{
Headers:map[string][]string{
echo.HeaderContentType:{echo.MIMEApplicationJSON},
},
JSONBody:[]byte(`{"name":"Jon Snow","email":"[email protected]"}`),
}.ToContextRecorder(t)
h :=&controller{mockDB}
// Assertions
if assert.NoError(t, h.createUser(c)){
assert.Equal(t, http.StatusCreated, rec.Code)
assert.Equal(t, userJSON+"\n", rec.Body.String())
}
}
// Same test as above but even shorter
funcTestCreateUserWithEchoTest2(t *testing.T){
h :=&controller{mockDB}
rec := echotest.ContextConfig{
Headers:map[string][]string{
echo.HeaderContentType:{echo.MIMEApplicationJSON},
},
JSONBody:[]byte(`{"name":"Jon Snow","email":"[email protected]"}`),
}.ServeWithHandler(t, h.createUser)
assert.Equal(t, http.StatusCreated, rec.Code)
assert.Equal(t, userJSON+"\n", rec.Body.String())
}
funcTestGetUser(t *testing.T){
// Setup
e := echo.New()
req := httptest.NewRequest(http.MethodGet,"/",nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
c.SetPath("/users/:email")
c.SetPathValues(echo.PathValues{
{Name:"email", Value:"[email protected]"},
})
h :=&controller{mockDB}
// Assertions
if assert.NoError(t, h.getUser(c)){
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, userJSON, rec.Body.String())
}
}
funcTestGetUserWithEchoTest(t *testing.T){
c, rec := echotest.ContextConfig{
PathValues: echo.PathValues{
{Name:"email", Value:"[email protected]"},
},
Headers:map[string][]string{
echo.HeaderContentType:{echo.MIMEApplicationJSON},
},
JSONBody:[]byte(userJSON),
}.ToContextRecorder(t)
h :=&controller{mockDB}
// Assertions
if assert.NoError(t, h.getUser(c)){
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, userJSON+"\n", rec.Body.String())
}
}
Using Form Payload
// import "net/url"
f :=make(url.Values)
f.Set("name","Jon Snow")
f.Set("email","[email protected]")
req := httptest.NewRequest(http.MethodPost,"/", strings.NewReader(f.Encode()))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationForm)
Multipart form payload:
funcTestContext_MultipartForm(t *testing.T){
testConf := echotest.ContextConfig{
MultipartForm:&echotest.MultipartForm{
Fields:map[string]string{
"key":"value",
},
Files:[]echotest.MultipartFormFile{
{
Fieldname:"file",
Filename:"test.json",
Content: echotest.LoadBytes(t,"testdata/test.json"),
},
},
},
}
c := testConf.ToContext(t)
assert.Equal(t,"value", c.FormValue("key"))
assert.Equal(t, http.MethodPost, c.Request().Method)
assert.Equal(t,true, strings.HasPrefix(c.Request().Header.Get(echo.HeaderContentType),"multipart/form-data; boundary="))
fv, err := c.FormFile("file")
if err !=nil{
t.Fatal(err)
}
assert.Equal(t,"test.json", fv.Filename)
}
Setting Path Params
c.SetPathValues(echo.PathValues{
{Name:"id", Value:"1"},
{Name:"email", Value:"[email protected]"},
})
Setting Query Params
// import "net/url"
q :=make(url.Values)
q.Set("email","[email protected]")
req := httptest.NewRequest(http.MethodGet,"/?"+q.Encode(),nil)
Testing Middleware
funcTestCreateUserWithEchoTest2(t *testing.T){
handler :=func(c *echo.Context)error{
return c.JSON(http.StatusTeapot, fmt.Sprintf("email: %s", c.Param("email")))
}
middleware :=func(next echo.HandlerFunc) echo.HandlerFunc {
returnfunc(c *echo.Context)error{
c.Set("user_id",int64(1234))
returnnext(c)
}
}
c, rec := echotest.ContextConfig{
PathValues: echo.PathValues{{Name:"email", Value:"[email protected]"}},
}.ToContextRecorder(t)
err :=middleware(handler)(c)
if err !=nil{
t.Fatal(err)
}
// check that middleware set the value
userID, err := echo.ContextGet[int64](c,"user_id")
assert.NoError(t, err)
assert.Equal(t,int64(1234), userID)
// check that handler returned the correct response
assert.Equal(t, http.StatusTeapot, rec.Code)
}
For now you can look into built-in middleware test cases.