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
$
@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
Please consider the PR https://github.com/gin-gonic/gin/pull/707
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?
Hi all, already fixed by https://github.com/gin-gonic/gin/pull/707
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.