猿问

使用 gorilla/mux URL 参数的函数的单元测试

gorilla/mux 过去不提供设置 URL 变量的可能性。现在确实如此,这就是为什么在很长一段时间内,第二高票数的答案都是正确的答案。


要遵循的原始问题:


这是我想要做的:


main.go


package main


import (

    "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 main


import (

    "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>

             

        

FAIL

FAIL    command-line-arguments  0.045s


30秒到达战场
浏览 271回答 3
3回答

慕斯王

gorilla/mux提供SetURLVars用于测试目的的函数,您可以使用它来注入您的 mock vars。func TestGetRequest(t *testing.T) {&nbsp; &nbsp; t.Parallel()&nbsp; &nbsp; r, _ := http.NewRequest("GET", "/test/abcd", nil)&nbsp; &nbsp; w := httptest.NewRecorder()&nbsp; &nbsp; //Hack to try to fake gorilla/mux vars&nbsp; &nbsp; vars := map[string]string{&nbsp; &nbsp; &nbsp; &nbsp; "mystring": "abcd",&nbsp; &nbsp; }&nbsp; &nbsp; // CHANGE THIS LINE!!!&nbsp; &nbsp; r = mux.SetURLVars(r, vars)&nbsp; &nbsp; GetRequest(w, r)&nbsp; &nbsp; assert.Equal(t, http.StatusOK, w.Code)&nbsp; &nbsp; assert.Equal(t, []byte("abcd"), w.Body.Bytes())}

一只萌萌小番薯

问题是,即使您使用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 {&nbsp; &nbsp; r := mux.Router()&nbsp; &nbsp; r.HandleFunc("/employees/{1}", GetRequest)&nbsp; &nbsp; (...)&nbsp; &nbsp; return r&nbsp;}在 main 函数的某个地方,你会做这样的事情:http.Handle("/", Router())在您的测试中,您可以执行以下操作:func TestGetRequest(t *testing.T) {&nbsp; &nbsp; r := http.NewRequest("GET", "employees/1", nil)&nbsp; &nbsp; w := httptest.NewRecorder()&nbsp; &nbsp; Router().ServeHTTP(w, r)&nbsp; &nbsp; // 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) {&nbsp; &nbsp; vars := mux.Vars(r)&nbsp; &nbsp; vh(w, r, vars)}要注册处理程序,您将使用:func GetRequest(w http.ResponseWriter, r *http.Request, vars map[string]string) {&nbsp; &nbsp; // process request using vars}mainRouter := mux.NewRouter().StrictSlash(true)mainRouter.HandleFunc("/test/{mystring}", VarsHandler(GetRequest)).Name("/test/{mystring}").Methods("GET")您使用哪一种取决于个人喜好。就我个人而言,我可能会选择选项 2 或 3,稍微偏向于选项 3。

慕后森

在 golang 中,我的测试方法略有不同。我稍微重写了你的 lib 代码:package mainimport (&nbsp; &nbsp; &nbsp; &nbsp; "fmt"&nbsp; &nbsp; &nbsp; &nbsp; "net/http"&nbsp; &nbsp; &nbsp; &nbsp; "github.com/gorilla/mux")func main() {&nbsp; &nbsp; &nbsp; &nbsp; startServer()}func startServer() {&nbsp; &nbsp; &nbsp; &nbsp; mainRouter := mux.NewRouter().StrictSlash(true)&nbsp; &nbsp; &nbsp; &nbsp; mainRouter.HandleFunc("/test/{mystring}", GetRequest).Name("/test/{mystring}").Methods("GET")&nbsp; &nbsp; &nbsp; &nbsp; http.Handle("/", mainRouter)&nbsp; &nbsp; &nbsp; &nbsp; err := http.ListenAndServe(":8080", mainRouter)&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("Something is wrong : " + err.Error())&nbsp; &nbsp; &nbsp; &nbsp; }}func GetRequest(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; &nbsp; &nbsp; vars := mux.Vars(r)&nbsp; &nbsp; &nbsp; &nbsp; myString := vars["mystring"]&nbsp; &nbsp; &nbsp; &nbsp; w.WriteHeader(http.StatusOK)&nbsp; &nbsp; &nbsp; &nbsp; w.Header().Set("Content-Type", "text/plain")&nbsp; &nbsp; &nbsp; &nbsp; w.Write([]byte(myString))}这是对它的测试:package mainimport (&nbsp; &nbsp; &nbsp; &nbsp; "io/ioutil"&nbsp; &nbsp; &nbsp; &nbsp; "net/http"&nbsp; &nbsp; &nbsp; &nbsp; "testing"&nbsp; &nbsp; &nbsp; &nbsp; "time"&nbsp; &nbsp; &nbsp; &nbsp; "github.com/stretchr/testify/assert")func TestGetRequest(t *testing.T) {&nbsp; &nbsp; &nbsp; &nbsp; go startServer()&nbsp; &nbsp; &nbsp; &nbsp; client := &http.Client{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Timeout: 1 * time.Second,&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; r, _ := http.NewRequest("GET", "http://localhost:8080/test/abcd", nil)&nbsp; &nbsp; &nbsp; &nbsp; resp, err := client.Do(r)&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; assert.Equal(t, http.StatusOK, resp.StatusCode)&nbsp; &nbsp; &nbsp; &nbsp; body, err := ioutil.ReadAll(resp.Body)&nbsp; &nbsp; &nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; panic(err)&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; assert.Equal(t, []byte("abcd"), body)}我认为这是一个更好的方法——你真的在测试你写的东西,因为它很容易在 go 中启动/停止侦听器!
随时随地看视频慕课网APP

相关分类

Go
我要回答