当前位置:   GIT > 正文

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

unit-testing,go,gorilla,testify,git,服务器,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间戳,在线开发工具,前端开发工具,开发人员工具,站长工具

这是我正在尝试做的事情:

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) 


FAIL
FAIL    command-line-arguments  0.045s

问题是如何伪造mux.Vars(r)单元测试?我在这里找到了一些讨论,但建议的解决方案不再适用.建议的解决方案是:

func buildRequest(method string, url string, doctype uint32, docid uint32) *http.Request {
    req, _ := http.NewRequest(method, url, nil)
    req.ParseForm()
    var vars = map[string]string{
        "doctype": strconv.FormatUint(uint64(doctype), 10),
        "docid":   strconv.FormatUint(uint64(docid), 10),
    }
    context.DefaultContext.Set(req, mux.ContextKey(0), vars) // mux.ContextKey exported
    return req
}

此解决方案不起作用context.DefaultContext,mux.ContextKey因此不再存在.

另一个建议的解决方案是更改代码,以便请求函数也接受map[string]string第三个参数.其他解决方案包括实际启动服务器并构建请求并将其直接发送到服务器.在我看来,这将破坏单元测试的目的,将它们基本上转变为功能测试.

考虑到链接线程来自2013年的事实.还有其他选择吗?

编辑

所以我已经阅读了gorilla/mux源代码,并根据mux.go函数在这里mux.Vars()定义如下:

// Vars returns the route variables for the current request, if any.
func Vars(r *http.Request) map[string]string {
    if rv := context.Get(r, varsKey); rv != nil {
        return rv.(map[string]string)
    }
    return nil
}

varsKey被定义为iota 在这里.基本上,关键值是0.我写了一个小测试应用来检查这个: main.go

package main

import (
    "fmt"
    "net/http"

    "github.com/gorilla/mux"
    "github.com/gorilla/context"
)

func main() {
    r, _ := http.NewRequest("GET", "/test/abcd", nil)
    vars := map[string]string{
        "mystring": "abcd",
    }
    context.Set(r, 0, vars)
    what := Vars(r)

    for key, value := range what {
        fmt.Println("Key:", key, "Value:", value)
    }

    what2 := mux.Vars(r)
    fmt.Println(what2)

    for key, value := range what2 {
        fmt.Println("Key:", key, "Value:", value)
    }

}

func Vars(r *http.Request) map[string]string {
    if rv := context.Get(r, 0); rv != nil {
        return rv.(map[string]string)
    }
    return nil
}

运行时,输出:

Key: mystring Value: abcd
map[]

这让我想知道为什么测试不起作用以及为什么直接调用mux.Vars不起作用.



1> del-boy..:

麻烦的是,即使您使用0值作为设置上下文值,它也不是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.



2> 小智..:

您需要将测试更改为:

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())
}

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/GIT/detail/13041
推荐阅读
  • 如何解决《CoordinatorLayout在另一个CoordinatorLayout里面》经验,为你挑选了3个好方法。android,android-viewpager,android-coordinatorlayout,android-... [详细]

  • 如何解决《Unity2d游戏中奇怪的碰撞错误》经验,为你挑选了1个好方法。c#,collision-detection,unity3d,git,算法,编辑器,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解... [详细]

  • 如何解决《为什么sbt编译失败并出现StackOverflowError?》经验,为你挑选了1个好方法。scala,sbt,xss,git,https,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二... [详细]

  • 如何解决《如何将包含现有文件的本地项目导入Source树》经验,为你挑选了1个好方法。git,tree,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间戳,在线开发工具,前端开发... [详细]

  • 如何解决《JQueryJSON获取嵌套值》经验,为你挑选了1个好方法。javascript,jquery,json,git,https,ajax,go,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二... [详细]

  • 如何解决《如何在使用asp.netIdentity关闭浏览器后保留登录信息?》经验,为你挑选了0个好方法。c#,asp.net,asp.net-mvc,asp.net-identity,git,DevBox,在线流程图,编程,编程问答,程序... [详细]

  • 如何解决《扩展另一个应用程序的标题栏》经验,为你挑选了1个好方法。c#,pinvoke,titlebar,winforms,git,windows,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码... [详细]

  • 如何解决《Elixir宏扩展问题,但只是在理解》经验,为你挑选了0个好方法。macros,elixir,git,erlang,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix时间戳,... [详细]

  • 如何解决《设置并使用Meld作为你的gitdifftool和mergetool》经验,为你挑选了4个好方法。git,meld,linux,windows,https,bash,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开... [详细]

  • 如何解决《是否可以使用window.onerror获取局部变量和参数值》经验,为你挑选了2个好方法。javascript,exception,ajax,git,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json... [详细]

  • 如何解决《即使在大括号中也显示strace中的完整参数》经验,为你挑选了2个好方法。linux,strace,git,bootstrap,go,https,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析... [详细]

  • 如何解决《Docker容器内的码头工人》经验,为你挑选了1个好方法。docker,dockerfile,容器,centos,https,git,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成... [详细]

  • 如何解决《带有Plus(+)字符的Android数字键盘》经验,为你挑选了1个好方法。android,android-keypad,android-number-picker,git,DevBox,在线流程图,编程,编程问答,程序员,开发者... [详细]

  • 如何解决《缺少对hdf5:totem的依赖》经验,为你挑选了1个好方法。hdf5,totem,lua,linux,https,git,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,unix... [详细]

  • 如何解决《JSPM和Typescript导入》经验,为你挑选了0个好方法。typescript,systemjs,angular,bootstrap,webstorm,npm,html,json,git,DevBox,在线流程图,编程,编程... [详细]

  • 如何解决《RealmObject的Kotlin数据类》经验,为你挑选了1个好方法。android,realm,kotlin,data-class,https,git,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,j... [详细]

  • 如何解决《Neurolab重新训练网络》经验,为你挑选了0个好方法。python,machine-learning,neural-network,神经网络,git,go,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具... [详细]

  • 如何解决《ngModel:''没有值访问器》经验,为你挑选了2个好方法。angular,https,git,bootstrap,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成... [详细]

  • 如何解决《如何使用puppet为不同的用户设置自定义bash环境?》经验,为你挑选了0个好方法。puppet,vagrant,bash,git,ubuntu,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解... [详细]

  • 如何解决《GithubAppforMac中的"Cherry-pick"》经验,为你挑选了0个好方法。git,github,DevBox,在线流程图,编程,编程问答,程序员,开发者工具,开发工具,json解析,二维码生成,... [详细]

相关标签
  

闽ICP备14008679号