Closed danielalves closed 7 years ago
I've been meaning to ask this as well. My way of testing my middleware usually looks something like this
func TestFooMiddleware(t *testing.T) {
gin.SetMode(gin.TestMode)
router := gin.New()
router.Use(FooMiddleware()) //only use the mw I want to test
router.GET("/test", func(c *gin.Context) {
c.String(200, "OK")
}
w := httptest.NewRecorder()
r, _ := http.NewRequest("GET", "/test", body)
router.ServeHTTP(w, r)
//assertions here
}
Is this the correct way of testing middleware in gin?
@slimmy I think your code is the correct way. You can not test how a middleware aborts if you are using a fake context.
@danielalves I will merge your PR but you should understand the limitations. createTestContext() was created to test the context itself.
You can not test if the context stops the execution (since there is not a handler chain associated). Like you should still use the code proposed by @slimmy if you have an authorisation middleware that validates the credentials.
@manucorporat Hey! Ok, I understand the limitations, but it is just what I need. For example, many of my tests look like this:
func mockContext(params map[string]string) (*gin.Context, *httptest.ResponseRecorder) {
gin.SetMode(gin.TestMode)
context, responseRecorder, _ := gin.CreateTestContext()
var paramsSlice []gin.Param
for key, value := range params {
paramsSlice = append(paramsSlice, gin.Param{
Key: key,
Value: value,
})
}
context.Params = paramsSlice
return context, responseRecorder
}
func TestCustomerController_CardById(t *testing.T) {
Convey("CardById", t, func() {
Convey("Handles invalid parameters", func() {
Convey("It returns NotFound for string customerId", func() {
mockedContext, responseRecorder := mockContext(map[string]string{
"customerId": "some-crazy-thing",
"cardId": kTEST_CARD_ID,
})
CardById(mockedContext)
cardJson := responseRecorder.Body.String()
So(cardJson, ShouldBeBlank)
So(responseRecorder.Code, ShouldEqual, http.StatusNotFound)
})
})
})
})
func CardById(c *gin.Context) {
// Router handler code
// ...
}
This is just a simple example, but I'm sure you can understand how I would implement tests for checking the validity of jsons and etc. (Oh, I'm trying goconvey for tests, so don't mind all the Convey
s :smile: )
@manucorporat Sorry to bother, but any updates on this?
I just wanted to add that using router.ServeHTTP(w, req)
to test route handlers may be the most correct way (as in the link you've sent above) since the request goes all the way through the gin stack, but isn't it a little overkill for simple unit tests? I mean, for acceptance tests, where you do want to test everything together, that makes perfect sense. But, for unit tests, wouldn't it be simpler as I've suggested on my last comment? Afterall, I want to test just the handler behavior, not its behavior with other middlewares and etc
+1 for this
Actually this would help make better unit tests.
I agree using httptest.Recorder
is the right way most of the times but sometimes it is useful testing if my custom middleware actually sets the right values through func (c *Context) Set(key string, value interface{})
without having to check status codes which may not make sense with that case.
@manucorporat can you suggest the best way to test middleware functions - i.e. I don't necessarily want to build up a whole http stack, just test a function where I pass in the context and manipulate the context, and then assert some state on the context after the function.
i'm trying to figure out from this thread here the most appropriate way to create a context without building up a whole stack.
Hello,
I understand all the benefits from having this as an exported function, but I have just run into an annoying side effect: since the function CreateTestContext() imports "net/http/httptest", it also adds an entry in cli arguments (https://golang.org/src/net/http/httptest/server.go#L69), which messes up with my cli arguments in my program.
Thoughts?
Please consider the PR https://github.com/gin-gonic/gin/pull/707
It make CreateTestContext()
public without importing net/http/httptest
how about any udpate?
How about making Context an interface, so I could pass a mock implementation to test my middlewares?
Hi All,
Thanks for this!
I'm trying to write tests for my controllers (using Gin, a file that groups route handlers), but I'm not being able to mock gin Contexts. Inside the context_test.go file, there's a method that does exactly that:
But it is not exported. I also cannot replicate it because
allocateContext
and Context'sengine
field are unexported too.What do you think about creating a test-helpers module and exporting
createTestContext
?