在使用Go語言編寫Web應用程式時,我們經常會用到gin框架來處理HTTP請求和回應。在進行單元測試時,我們需要對程式碼進行覆蓋測試,以確保程式碼的品質和穩定性。然而,針對gin的Context.Redirect方法的單元測試在處理GET請求時非常適用,但在處理POST請求時卻不太適用。在本文中,php小編蘋果將會詳細解釋為什麼這個問題會出現,並提供一些解決方案來進行POST請求的單元測試。
我希望我的伺服器將特定端點重定向到另一台伺服器。這個端點可以是 get
ted 或 post
ed。在這兩種情況下,http 回應碼都應為 302。如果我在此程式碼上使用 curl
,它確實在兩種情況下都顯示回應代碼 302,並且 curl -l
正確遵循重定向。哇哦。
但是
我的單元測試使用httptest.newrecorder()
來捕獲訊息,但它僅適用於get
,不適用於post
。因此,當我知道實際的重定向正在工作時,我需要弄清楚如何讓單元測試工作。失敗測試顯示http回應碼是200而不是302(http.statusfound
)。
$ go run foo.go post code 200 get code 302
這是獨立測試。
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") } }
當我在實際應用程式(未顯示)上執行 curl post 時,我發現它正在工作:
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
解決方法是在 context.redirect
之後明確呼叫 context.writer.writeheadernow
。
這是使用從 gin.createtestcontext
傳回的 gin 上下文的一個極端情況。
對於get 請求,gin 最終會呼叫http.redirect
,它將向回應寫入一個簡短的html 正文(類似於<a href="http://foobar. com">found</a>
),從而導致要寫入回應的狀態碼。
對於 post 請求,http.redirect
不會寫入短 html 正文,且狀態碼沒有機會寫入回應。
請參考http 的實作.重定向。根據原始碼,如果之前設定了content-type
header,那麼get請求也會出現相同的問題:
{ 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") }
解決方法是明確呼叫 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 本身使用相同的解決方法。請參閱 testcontextrenderredirectwithrelativepath。
真正的伺服器應用程式不會遇到相同的問題,因為(*engine).handlehttprequest
將為我們呼叫writeheadernow
(請參閱原始碼)。這就是為什麼我稱其為“極端情況”而不是“錯誤”。
以上是gin 的 Context.Redirect 的單元測試適用於 GET 回應代碼,但不適用於 POST 回應代碼 (golang)的詳細內容。更多資訊請關注PHP中文網其他相關文章!