Search code examples
gotestinggo-gingo-testing

Why my test with Gin and Go is not passing?


I am trying to test my API. In this case, I have this main file:

package main

import (
    "fmt"
    "net/http"

    "github.com/gin-gonic/gin"
)

func main() {
    r := getRouter()
    r.Run(":8080")
}

func getRouter() *gin.Engine {
    // We create the instance for Gin
    r := gin.Default()

    // Path to the static files. /static is rendered in the HTML and /media is the link to the path to the  images, svg, css.. the static files
    r.StaticFS("/static", http.Dir("../media"))

    // Path to the HTML templates. * is a wildcard
    r.LoadHTMLGlob("*.html")

    r.NoRoute(renderHome)
    // This get executed when the users gets into our website in the home domain ("/")
    r.GET("/", renderHome)
    r.POST("/", getData)
    return r
}

func renderHome(c *gin.Context) {
    c.HTML(http.StatusOK, "my-html.html", gin.H{})
}

func getData(c *gin.Context) {
    formData := &struct {
        ID int `json:"mykey"  binding:"required" `
    }{}
    // Validation (with Gin)
    if err := c.Bind(formData); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        fmt.Print(err)
        return
    }
}

And I have this main_test file

package main

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

    "github.com/stretchr/testify/assert"
)

func TestPost(t *testing.T) {
    // Create Infraestructure
    router := getRouter()
    w := httptest.NewRecorder()
    // Rent Bike
    body := bytes.NewBuffer([]byte("{\"mykey\":1}"))
    req, _ := http.NewRequest("POST", "/", body)
    router.ServeHTTP(w, req)
    // Test data
    assert.Equal(t, http.StatusOK, w.Code)
}

The test is failing because when binding, Gin does not find mykey json key, giving the error Key: 'ID' Error:Field validation for 'ID' failed on the 'required' tag

Why is that happening? I tried formatting the JSON body in different ways and I coul not make it work


Solution

  • Gin chooses which binding to use based on the request Content-Type.

    When using the Bind-method, Gin tries to infer the binder depending on the Content-Type header. If you are sure what you are binding, you can use MustBindWith or ShouldBindWith.

    Change your code to:

        req, err := http.NewRequest("POST", "/", body)
        require.Nil(t, err)
        req.Header.Set("Content-Type", "application/json")
        router.ServeHTTP(w, req)