When writing web applications in Go language, we often use the gin framework to handle HTTP requests and responses. When performing unit testing, we need to perform coverage testing on the code to ensure the quality and stability of the code. However, the unit test for gin's Context.Redirect method works great when handling GET requests, but not so well when handling POST requests. In this article, PHP editor Apple will explain in detail why this problem occurs and provide some solutions to unit test POST requests.
I want my server to redirect a specific endpoint to another server. The endpoint can be get
ted or post
ed. In both cases, the http response code should be 302. If I use curl
on this code, it does show response code 302 in both cases, and curl -l
follows the redirect correctly. Wow.
but
My unit test uses httptest.newrecorder()
to capture the information, but it only works with get
, not post
. So I need to figure out how to get the unit tests to work when I know the actual redirection is working. The failing test shows that the http response code is 200 instead of 302 (http.statusfound
).
$ go run foo.go post code 200 get code 302
This is an independent test.
package main import ( "net/http" "net/http/httptest" "github.com/gin-gonic/gin" ) func main() { gin.setmode(gin.releasemode) { w := httptest.newrecorder() context, _ := gin.createtestcontext(w) context.request = httptest.newrequest("post", "http://localhost:23632/foobar", nil) context.redirect(http.statusfound, "http://foobar.com") print("post code ",w.code,"\n") } { w := httptest.newrecorder() context, _ := gin.createtestcontext(w) context.request = httptest.newrequest("get", "http://localhost:23632/foobar", nil) context.redirect(http.statusfound, "http://foobar.com") print("get code ",w.code,"\n") } }
When I execute curl post on the actual application (not shown) I see that it is working:
curl -v -XPOST localhost:23632/foobar * About to connect() to localhost port 23632 (#0) * Trying 127.0.0.1... * Connected to localhost (127.0.0.1) port 23632 (#0) > POST /foobar HTTP/1.1 > User-Agent: curl/7.29.0 > Host: localhost:23632 > Accept: */* > < HTTP/1.1 302 Found < Location: http://foobar.com < Vary: Origin < Date: Tue, 23 May 2023 22:38:42 GMT < Content-Length: 0 < * Connection #0 to host localhost left intact
The solution is to explicitly call context.writer.writeheadernow
after context.redirect
.
This is an edge case of using the gin context returned from gin.createtestcontext
.
For get requests, gin will eventually call http.redirect
, which will write a short html body to the response (similar to <a href="http://foobar. com">found</a>
), causing the response's status code to be written.
For post requests, http.redirect
no short html body is written, and the status code does not have a chance to be written to the response.
See http implementation. Redirection. According to the source code, if the content-type
header was set before, the same problem will occur with the get request:
{ w := httptest.newrecorder() context, _ := gin.createtestcontext(w) context.request = httptest.newrequest("get", "http://localhost:23632/foobar", nil) + context.header("content-type", "text/html") context.redirect(http.statusfound, "http://foobar.com") print("get code ", w.code, "\n") }
The solution is to explicitly call context.writer.writeheadernow
:
{ w := httptest.NewRecorder() context, _ := gin.CreateTestContext(w) context.Request = httptest.NewRequest("POST", "http://localhost:23632/foobar", nil) context.Redirect(http.StatusFound, "http://foobar.com") + context.Writer.WriteHeaderNow() print("POST code ", w.Code, "\n") }
gin itself uses the same workaround. See testcontextrenderredirectwithrelativepath.
A real server application won't suffer from the same problem, because (*engine).handlehttprequest
will call writeheadernow
for us (see source code). That's why I call it an "edge case" rather than a "bug".
The above is the detailed content of Unit test for gin's Context.Redirect works for GET response codes but not for POST response codes (golang). For more information, please follow other related articles on the PHP Chinese website!