【问题标题】:Testing Chi Routes w/Path Variables使用路径变量测试 Chi 路线
【发布时间】:2019-02-07 19:09:36
【问题描述】:

我无法测试我的 go-chi 路线,特别是带有路径变量的路线。使用go run main.go 运行服务器可以正常工作,并且对带有路径变量的路由的请求行为符合预期。

当我为路由运行测试时,我总是收到 HTTP 错误:Unprocessable Entity。在注销articleID 发生的事情后,articleCtx 似乎无法访问路径变量。不确定这是否意味着我需要在测试中使用articleCtx,但我尝试过ArticleCtx(http.HandlerFunc(GetArticleID)) 并得到错误:

panic: interface conversion: interface {} is nil, not *chi.Context [recovered] panic: interface conversion: interface {} is nil, not *chi.Context

运行服务器:go run main.go

测试服务器:go test .

我的来源:

// main.go

package main

import (
    "context"
    "fmt"
    "net/http"
    "strconv"

    "github.com/go-chi/chi"
)

type ctxKey struct {
    name string
}

func main() {
    r := chi.NewRouter()

    r.Route("/articles", func(r chi.Router) {
        r.Route("/{articleID}", func(r chi.Router) {
            r.Use(ArticleCtx)
            r.Get("/", GetArticleID) // GET /articles/123
        })
    })

    http.ListenAndServe(":3333", r)
}

// ArticleCtx gives the routes using it access to the requested article ID in the path
func ArticleCtx(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        articleParam := chi.URLParam(r, "articleID")
        articleID, err := strconv.Atoi(articleParam)
        if err != nil {
            http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
            return
        }

        ctx := context.WithValue(r.Context(), ctxKey{"articleID"}, articleID)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

// GetArticleID returns the article ID that the client requested
func GetArticleID(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    articleID, ok := ctx.Value(ctxKey{"articleID"}).(int)
    if !ok {
        http.Error(w, http.StatusText(http.StatusUnprocessableEntity), http.StatusUnprocessableEntity)
        return
    }

    w.Write([]byte(fmt.Sprintf("article ID:%d", articleID)))
}
// main_test.go

package main

import (
    "fmt"
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestGetArticleID(t *testing.T) {
    tests := []struct {
        name           string
        rec            *httptest.ResponseRecorder
        req            *http.Request
        expectedBody   string
        expectedHeader string
    }{
        {
            name:         "OK_1",
            rec:          httptest.NewRecorder(),
            req:          httptest.NewRequest("GET", "/articles/1", nil),
            expectedBody: `article ID:1`,
        },
        {
            name:         "OK_100",
            rec:          httptest.NewRecorder(),
            req:          httptest.NewRequest("GET", "/articles/100", nil),
            expectedBody: `article ID:100`,
        },
        {
            name:         "BAD_REQUEST",
            rec:          httptest.NewRecorder(),
            req:          httptest.NewRequest("PUT", "/articles/bad", nil),
            expectedBody: fmt.Sprintf("%s\n", http.StatusText(http.StatusBadRequest)),
        },
    }

    for _, test := range tests {
        t.Run(test.name, func(t *testing.T) {
            ArticleCtx(http.HandlerFunc(GetArticleID)).ServeHTTP(test.rec, test.req)

            if test.expectedBody != test.rec.Body.String() {
                t.Errorf("Got: \t\t%s\n\tExpected: \t%s\n", test.rec.Body.String(), test.expectedBody)
            }
        })
    }
}

不知道如何继续。有任何想法吗?我想知道net/http/httptest 中是否有关于使用context 进行测试的答案,但什么也没看到。

也是非常新的 go Go(和 context 包),因此非常感谢任何代码审查/最佳实践 cmets :)

【问题讨论】:

  • 路由器提供了获取变量的能力,这就是为什么r被传递给chi.URLParam,但是在你的测试中你根本没有设置路由器,所以全局实例路由器不知道“articleID”,因为您尚未使用该密钥注册任何模式。

标签: rest go go-chi


【解决方案1】:

有一个类似的问题,虽然我是直接对处理程序进行单元测试。基本上,当使用 httptest.NewRequest 强制您手动添加它们时,似乎 url 参数不会自动添加到请求上下文中。

以下内容对我有用。

w := httptest.NewRecorder()
r := httptest.NewRequest("GET", "/{key}", nil)

rctx := chi.NewRouteContext()
rctx.URLParams.Add("key", "value")

r = r.WithContext(context.WithValue(r.Context(), chi.RouteCtxKey, rctx))

handler := func(w http.ResponseWriter, r *http.Request) {
    value := chi.URLParam(r, "key")
}
handler(w, r)

感谢soedar here =)

【讨论】:

    【解决方案2】:

    命名路径变量也有同样的问题。我能够解决它为我的测试设置路由器。 go-chi 测试显示了一个很好的样本。

    Go Chi Sample test with URL params

    【讨论】:

      【解决方案3】:

      main 中,您在定义路径/articles 后指示使用ArticleCtx,但在您的测试中,您只是直接使用ArticleCtx

      您的测试请求不应包含/articles,例如:

      httptest.NewRequest("GET", "/1", nil)

      【讨论】:

        猜你喜欢
        • 2018-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多