我无法测试我的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
软件包)也很新,因此,非常感谢任何代码审查/最佳实践注释:)
答案 0 :(得分:0)
命名路径变量也有同样的问题。我能够解决它,为我的测试设置路由器。 go-chi测试显示出很好的样本。
答案 1 :(得分:0)
在 main
中,您在定义路径 ArticleCtx
后指示使用 /articles
,但在您的测试中,您只是直接使用 ArticleCtx
。
您的测试请求不应包含 /articles
,例如:
httptest.NewRequest("GET", "/1", nil)