我无法测试我的 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
包),因此非常感谢任何代码审查/最佳实践评论:)