Gin: test_helpers.go should be named helpers_test.go

Created on 7 Apr 2016  路  20Comments  路  Source: gin-gonic/gin

test_helpers.go is built with the package. It should be built only when testing which means it should have the suffix _test.go. One side effect is that is that by test_helpers.go using httptest every program that uses gin gets -httptest.serve flag.

package main

import (
    "flag"
    "net/http"

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

func main() {
    rtr := gin.Default()
    rtr.GET("/", func(ctx *gin.Context) {
        ctx.String(http.StatusOK, "Hi")
    })
    flag.Parse()
    rtr.Run(":8080")
}

Now run the program with --help and you'll see:

$ go run /tmp/t.go --help
[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /                         --> main.main.func1 (3 handlers)
Usage of /tmp/go-build903640301/command-line-arguments/_obj/exe/t:
  -httptest.serve string
        if non-empty, httptest.NewServer serves on this address and blocks
exit status 2
$
bug

Most helpful comment

There's a need to name it as test_helpers.go not helpers_test.go. Unit test on a package using gin will need to create test context. By renaming it to helpers_test.go CreateTestContext() becomes private.

Since CreateTestContext() refers to private methods, package user now can't create his own test context.

All 20 comments

@tebeka thank you for noticing this, merging #581

There's a need to name it as test_helpers.go not helpers_test.go. Unit test on a package using gin will need to create test context. By renaming it to helpers_test.go CreateTestContext() becomes private.

Since CreateTestContext() refers to private methods, package user now can't create his own test context.

@roylou i didn't know that, there is any resource I can check?

By renaming it to helpers_test.go CreateTestContext() becomes private.

Even when the first letter of the function name is capital?

@javierprovecho unfortunately I couldn't find any web resource. This is by self exploration.

If you run "go test" of the following foo_test.go:

package foo

import (
    "fmt"
    "github.com/gin-gonic/gin"
)

func TestCreateContext() {
    c, w, r := gin.CreateTestContext()
    fmt.Println(c, w, r)
}

It'll complain
./foo_test.go:9: undefined: gin.CreateTestContext

Maybe move this to "github.com/gin-gonic/gin/test" package then? This way people will be able to use it in testing but it won't show up by application code using gin?

This unfortunately won't work. CreateTestContext() invokes some of gin's private function. Putting it out of github.com/gin-gonic/gin will block private function accessibility.

I think exposing -httptest.serve flag is a worthy trade-off given today's golang rule. Your program already shows 100+ flags depending on the number of third-party libs. 90% of them you don't really care. Adding a test flag into those 90% isn't ideal but tolerable to me.

I disagree. I think we should find a cleaner API and make it work.

The merge of #581 has broken a my tests because they relied on CreateTestContext(). Is there a workaround?

Seems there's trade off between API cleanness and testibility. Please let me know if there's better way to maintain testibility. Without CreateTestContext(), I'll need to really start a fake http server instead of testing against my gin router function.

I too am missing the existence of this function. The fact that gin handlers only need to take a Context is part of what attracted me to it. The lack of an easy way to create a context for testing purposes seems like a regression to me.

I am guessing from the lack of interest in this issue, that application code that uses gin remains untestable?

IMO we should revert to the old state where CreateTestContext is exposed until we find a better/cleaner way to do it. Any objections?

That would be good for me - thanks.

You can use gin's ServeHTTP function to simulate a request:

func getGinRouter() *gin.Engine {
    r := gin.Default()
    r.Post("/", func (c *gin.Context) { c.String(200, "Hello") })
    return r
}

func newTestContext(method, path string) (w *httptest.ResponseRecorder, r *http.Request) {
    w = httptest.NewRecorder()
    r, _ = http.NewRequest(method, path, nil)
    r.PostForm = url.Values{}
    return
}

func TestIndex(t *testing.T) {
    w, r := newTestContext("POST", "/")
    r.PostForm.Add("a_param", "a_value")
    getGinRouter().ServeHTTP(w, r)
    assert.Equal(t, 200, w.Code)
    assert.Equal(t, "Hello", w.Body.String())
}

I only miss the ability to access gin's context inside my tests. Otherwise, it works very well.

A section about how to write tests with Gin would be important for new users.

Why not make CreateTestContext() to receive a http.ResponseWriter object?

func CreateTestContext(w http.ResponseWriter) (c *Context, r *Engine) {
    r = New()
    c = r.allocateContext()
    c.reset()
    c.writermem.reset(w)
    return
}

When testing, create a new httptest.NewRecorder() and pass it to CreateTestContext()

w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)

This means test_helpers.go doesn't need to import net/http/httptest

any update on it? need this exported func CreateTestContext

I also need CreateTestContext to test my handler independent of the http router/application. Any updates?

Was this page helpful?
0 / 5 - 0 ratings