【问题标题】:Testing handlers that use Gorilla/context测试使用 Gorilla/context 的处理程序
【发布时间】:2016-09-23 08:17:39
【问题描述】:

我在 Web 应用程序中使用 gorilla/context。文档中的示例如下所示:

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

    val := context.Get(r, foo.MyKey)

    //...
}

如何对像这样工作的处理程序进行单元测试?到目前为止,我管理的唯一方法是在我的测试中使用 context 包。我目前正在考虑可以将上下文参数注入处理程序,但我不符合 HandlerFunc 接口。

【问题讨论】:

    标签: go gorilla


    【解决方案1】:

    这是一个经典的cross-cutting concerns 示例。

    您正在使用第 3 方来神奇地处理被测单元的输入参数。根据这个定义,你将不得不做一些额外的设置来为你想要的状态准备context

    当涉及到 Go http 处理程序(约定是 KISS 它)时,您不需要“脱离上下文”来获取额外数据:将所需的所有数据保存在单个 func 中.

    就我个人而言,我尽量避免像这样破坏我的处理程序。我认为在我建立的数十个大型网站中,我只使用过一次大猩猩的上下文。这基本上是为了绕过缓存的响应,只是为了保持数据刷新给最终用户。在我的单元测试中我只是忽略了它,因为它超出了我正在测试的范围。

    相反,我使用中间件包装器在我的句柄中设置我想要的基础,并相应地修改处理程序的签名。

    • 缓存
    • 日志记录
    • 认证授权
    • json 封送处理
    • 上下文(例如,从数据库加载的预期 User{} 对象)

    ...等等。我会创建一个中间件,当您使用 mux 注册它时包装您的处理程序,它使用 gorilla/context 来查找您的 cookie 或用户 ID 或其他东西,从缓存、数据库、redis 等中隐藏该用户对象,然后调用您的具有如下签名的处理程序:

    func MyHandler(u User, p Page, w http.ResponseWriter, r *http.Request) {
        // u is the User object loaded from middle-ware
    
        // p is your global Page object... etc
    }
    

    这样,您的单元测试只注入您在测试中需要的项目。

    您可以在 QA 服务器上使用数据存储区中的预期用户和页面对象集成测试您的中间件。

    【讨论】:

    • 我认为我们正在按照您所说的进行工作。此刻,我们链接了从请求中获取所需数据并将其设置到上下文的中间件函数。我们应该将上下文中的值注入到处理程序中,而不是直接在处理程序内部访问上下文包,对吗?
    • 是的,我们就是这样做的。如果方法准确反映您在该处理程序中使用的内容,则保持句柄简单并具有签名。这就是其他语言的 MVC 框架定义 MVC 路由的方式。
    【解决方案2】:

    我的团队这样做的方式是为路由处理程序添加一个名称,然后在测试中我们按名称调用该路由。

    这是添加路线的方法:

    r.HandleFunc("/<route>", MyHandler).Methods("GET").Name("MyHandlerByName")

    那么这就是如何测试它

    r.Get("MyHandlerByName")

    【讨论】:

    • 我使用这种方法在代码中定义 URL,比如重定向。
    【解决方案3】:

    测试句柄的一种方法是修改它们的创建方式。例如,创建一个返回 http.HandlerFunc 的函数,该函数可以有参数。您可以模拟您发送给函数的值

    无参数

     func State() http.HandlerFunc {
            return http.HandlerFunc(func(pResponse http.ResponseWriter, r *http.Request)    {
                // your code
            })
        }
    

    带参数

       func State(pParam1,pParam2,pParam3 ...) http.HandlerFunc {
            return http.HandlerFunc(func(pResponse http.ResponseWriter, r *http.Request)    {
                // your code using pParam1,pParam2,pParam3 
            })
        }
    

    映射将是

    http.HandleFunc("/State", State())
    

    http.HandleFunc("/State", State(value1,value2,value3 ....))
    

    【讨论】:

    • 这是我的回答所描述的中间件。但是很好,你有例子。 :)
    猜你喜欢
    • 2017-04-20
    • 1970-01-01
    • 2013-12-23
    • 2020-08-26
    • 1970-01-01
    • 2023-01-20
    • 1970-01-01
    • 2017-03-28
    相关资源
    最近更新 更多