我在测试go-chi路线(特别是带有路径变量的路线)时遇到了麻烦。使用go run main.go
运行服务器可以正常工作,并且使用path变量对路由的请求的行为符合预期。
在对路由进行测试时,始终会收到HTTP错误:Unprocessable Entity
。在注销articleID
发生了什么之后,似乎articleCtx
无法访问path变量。不知道这是否意味着我需要在测试中使用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也很新(和
context
包),因此,任何代码复习/最佳实践注释都非常受人们欢迎:)
最佳答案
我对命名路径变量有同样的问题。我能够解决它,为我的测试设置路由器。格氏测试显示了一个很好的样本。
Go Chi Sample test with URL params
关于rest - 使用/路径变量测试Chi路线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54580582/