亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用 gorilla/mux URL 參數的函數的單元測試

使用 gorilla/mux URL 參數的函數的單元測試

Go
30秒到達戰場 2021-11-29 19:10:53
gorilla/mux 過去不提供設置 URL 變量的可能性。現在確實如此,這就是為什么在很長一段時間內,第二高票數的答案都是正確的答案。要遵循的原始問題:這是我想要做的:main.gopackage mainimport (    "fmt"    "net/http"        "github.com/gorilla/mux")    func main() {    mainRouter := mux.NewRouter().StrictSlash(true)    mainRouter.HandleFunc("/test/{mystring}", GetRequest).Name("/test/{mystring}").Methods("GET")    http.Handle("/", mainRouter)        err := http.ListenAndServe(":8080", mainRouter)    if err != nil {        fmt.Println("Something is wrong : " + err.Error())    }}func GetRequest(w http.ResponseWriter, r *http.Request) {    vars := mux.Vars(r)    myString := vars["mystring"]        w.WriteHeader(http.StatusOK)    w.Header().Set("Content-Type", "text/plain")    w.Write([]byte(myString))}這將創建一個基本的 http 服務器偵聽端口8080,該端口與路徑中給出的 URL 參數相呼應。因此,http://localhost:8080/test/abcd它將寫回包含abcd在響應正文中的響應。該GetRequest()函數的單元測試在main_test.go 中:package mainimport (    "net/http"    "net/http/httptest"    "testing"    "github.com/gorilla/context"    "github.com/stretchr/testify/assert")func TestGetRequest(t *testing.T) {    t.Parallel()        r, _ := http.NewRequest("GET", "/test/abcd", nil)    w := httptest.NewRecorder()    //Hack to try to fake gorilla/mux vars    vars := map[string]string{        "mystring": "abcd",    }    context.Set(r, 0, vars)        GetRequest(w, r)    assert.Equal(t, http.StatusOK, w.Code)    assert.Equal(t, []byte("abcd"), w.Body.Bytes())}測試結果是:--- FAIL: TestGetRequest (0.00s)    assertions.go:203:                             Error Trace:    main_test.go:27            Error:      Not equal: []byte{0x61, 0x62, 0x63, 0x64} (expected)                    != []byte(nil) (actual)                        Diff:            --- Expected            +++ Actual            @@ -1,4 +1,2 @@            -([]uint8) (len=4 cap=8) {            - 00000000  61 62 63 64                                       |abcd|            -}            +([]uint8) <nil>                     FAILFAIL    command-line-arguments  0.045s
查看完整描述

3 回答

?
慕斯王

TA貢獻1864條經驗 獲得超2個贊

gorilla/mux提供SetURLVars用于測試目的的函數,您可以使用它來注入您的 mock vars。


func TestGetRequest(t *testing.T) {

    t.Parallel()


    r, _ := http.NewRequest("GET", "/test/abcd", nil)

    w := httptest.NewRecorder()


    //Hack to try to fake gorilla/mux vars

    vars := map[string]string{

        "mystring": "abcd",

    }


    // CHANGE THIS LINE!!!

    r = mux.SetURLVars(r, vars)


    GetRequest(w, r)


    assert.Equal(t, http.StatusOK, w.Code)

    assert.Equal(t, []byte("abcd"), w.Body.Bytes())

}


查看完整回答
反對 回復 2021-11-29
?
一只萌萌小番薯

TA貢獻1795條經驗 獲得超7個贊

問題是,即使您使用0as 值來設置上下文值,mux.Vars()讀取的值也不是相同的。mux.Vars()正在使用varsKey(正如您已經看到的)類型contextKey而不是int.


當然,contextKey定義為:


type contextKey int

這意味著它具有 int 作為底層對象,但在比較 go 中的值時,類型會起作用,因此int(0) != contextKey(0).


我不明白你怎么能欺騙大猩猩多路復用器或上下文來返回你的值。


話雖如此,我想到了幾種測試方法(請注意,下面的代碼未經測試,我直接在此處輸入,因此可能存在一些愚蠢的錯誤):


正如有人建議的那樣,運行一個服務器并向它發送 HTTP 請求。

無需運行服務器,只需在測試中使用 gorilla mux Router。在這種情況下,您將有一個傳遞給 的路由器ListenAndServe,但您也可以在測試中使用相同的路由器實例并調用ServeHTTP它。路由器將負責設置上下文值,它們將在您的處理程序中可用。


func Router() *mux.Router {

    r := mux.Router()

    r.HandleFunc("/employees/{1}", GetRequest)

    (...)

    return r 

}

在 main 函數的某個地方,你會做這樣的事情:


http.Handle("/", Router())

在您的測試中,您可以執行以下操作:


func TestGetRequest(t *testing.T) {

    r := http.NewRequest("GET", "employees/1", nil)

    w := httptest.NewRecorder()


    Router().ServeHTTP(w, r)

    // assertions

}

包裝您的處理程序,以便它們接受 URL 參數作為第三個參數,并且包裝器應調用mux.Vars()URL 參數并將其傳遞給處理程序。


使用此解決方案,您的處理程序將具有簽名:


type VarsHandler func (w http.ResponseWriter, r *http.Request, vars map[string]string)

并且您必須調整對它的調用以符合http.Handler接口:


func (vh VarsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

    vars := mux.Vars(r)

    vh(w, r, vars)

}

要注冊處理程序,您將使用:


func GetRequest(w http.ResponseWriter, r *http.Request, vars map[string]string) {

    // process request using vars

}


mainRouter := mux.NewRouter().StrictSlash(true)

mainRouter.HandleFunc("/test/{mystring}", VarsHandler(GetRequest)).Name("/test/{mystring}").Methods("GET")

您使用哪一種取決于個人喜好。就我個人而言,我可能會選擇選項 2 或 3,稍微偏向于選項 3。


查看完整回答
反對 回復 2021-11-29
?
慕后森

TA貢獻1802條經驗 獲得超5個贊

在 golang 中,我的測試方法略有不同。


我稍微重寫了你的 lib 代碼:


package main


import (

        "fmt"

        "net/http"


        "github.com/gorilla/mux"

)


func main() {

        startServer()

}


func startServer() {

        mainRouter := mux.NewRouter().StrictSlash(true)

        mainRouter.HandleFunc("/test/{mystring}", GetRequest).Name("/test/{mystring}").Methods("GET")

        http.Handle("/", mainRouter)


        err := http.ListenAndServe(":8080", mainRouter)

        if err != nil {

                fmt.Println("Something is wrong : " + err.Error())

        }

}


func GetRequest(w http.ResponseWriter, r *http.Request) {

        vars := mux.Vars(r)

        myString := vars["mystring"]


        w.WriteHeader(http.StatusOK)

        w.Header().Set("Content-Type", "text/plain")

        w.Write([]byte(myString))

}

這是對它的測試:


package main


import (

        "io/ioutil"

        "net/http"

        "testing"

        "time"


        "github.com/stretchr/testify/assert"

)


func TestGetRequest(t *testing.T) {

        go startServer()

        client := &http.Client{

                Timeout: 1 * time.Second,

        }


        r, _ := http.NewRequest("GET", "http://localhost:8080/test/abcd", nil)


        resp, err := client.Do(r)

        if err != nil {

                panic(err)

        }

        assert.Equal(t, http.StatusOK, resp.StatusCode)

        body, err := ioutil.ReadAll(resp.Body)

        if err != nil {

                panic(err)

        }

        assert.Equal(t, []byte("abcd"), body)

}

我認為這是一個更好的方法——你真的在測試你寫的東西,因為它很容易在 go 中啟動/停止偵聽器!


查看完整回答
反對 回復 2021-11-29
  • 3 回答
  • 0 關注
  • 363 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號