mux.Vars 无法从 httpTest 请求中检索 var
mux.Vars is not able to retrieve var from httpTest request
我正在为未来的项目写一个简单的 rest 样板,我目前正在为我的控制器做一些测试,我试图通过它在 /todo/{id}
的 Id 检索待办事项,这是处理程序。
func (t TodoController) GetById(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id, err := strconv.Atoi(params["id"])
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
todo, err := t.todoService.GetById(id)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
helpers.SendResponse(http.StatusOK, todo, w)
}
下面是这个控制器的测试。
var (
todoController TodoController
recorder *httptest.ResponseRecorder
todos []models.Todo
)
func setup() {
todoController = *NewTodoController(services.NewTodoService())
recorder = httptest.NewRecorder()
todos = []models.Todo{
{
ID: 0,
Todo: "Buy milk",
Completed: false,
},
{
ID: 1,
Todo: "Buy cheese",
Completed: false,
},
{
ID: 2,
Todo: "Buy eggs",
Completed: false,
},
}
}
func TestGetById(t *testing.T) {
// Arrange
setup()
request := httptest.NewRequest(http.MethodGet, "/todo/1", nil)
var response models.Todo
// Act
todoController.GetById(recorder, request)
result := recorder.Result()
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
err = json.Unmarshal(data, &response)
// Assert
if err != nil {
t.Errorf("Expected error to be nil but got %v", err)
}
assert.Equal(t, result.StatusCode, http.StatusOK, "Response should have been 200 Ok")
assert.Equal(t, response, todos[1], "Response did not match the expected result")
}
向 /todo/1
发送请求时,mux 似乎无法检索 Id,因此它最终会返回 BadRequest 错误。
这是此回购的 link:https://github.com/Je12emy/rest_boiler
Mux 提供了两种注入请求参数的方法 - SetURLVars
帮助器和使用 mux.Router
包装器而不是直接调用处理程序。
SetURLVars 完全按照您的意愿行事 - 将否则无法访问的参数注入 HTTP 请求。
这个方法很简单,但是有一个问题。使用的 URL 和注入的参数不同步。
None 禁止开发者编写此代码:
// we use 2 in request path
request := httptest.NewRequest(http.MethodGet, "/todo/2", nil)
// and we use 1 in request param
request = SetURLVars(request, map[string]string{"id":"1"})
这不是很干净的测试实践。
我们不测试路由中的 var 名称是否正确。我们可以在路由器中使用 item_id
而不是 id
并且测试没有捕捉到它。
不仅如此,我们还可以在路由器定义中使用错误的路径并映射不同的处理程序。如果我们犯了这个错误,客户可以删除 order
而不是 todo
项。
如果我们在测试中使用我们的生产路由器,就可以解决这个问题。
假设是我们的生产代码:
func InitRouter(t TodoController) http.handler
r := mux.NewRouter()
r.HandleFunc("/todo/{id}", t.GetById).Methods(http.MethodGet)
return r
在测试中,我们可以通过我们在InitRouter
函数中创建的路由器来测试GetById
:
func TestGetById(t *testing.T) {
// Arrange
setup()
request := httptest.NewRequest(http.MethodGet, "/todo/1", nil)
var response models.Todo
// added setup
sut := InitRouter(todoController)
// Act
// changed act - calling GetById through production router
sut.ServeHTTP(recorder, request)
// no chnages after that
result := recorder.Result()
defer result.Body.Close()
...
}
我正在为未来的项目写一个简单的 rest 样板,我目前正在为我的控制器做一些测试,我试图通过它在 /todo/{id}
的 Id 检索待办事项,这是处理程序。
func (t TodoController) GetById(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id, err := strconv.Atoi(params["id"])
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
todo, err := t.todoService.GetById(id)
if err != nil {
w.WriteHeader(http.StatusNotFound)
return
}
helpers.SendResponse(http.StatusOK, todo, w)
}
下面是这个控制器的测试。
var (
todoController TodoController
recorder *httptest.ResponseRecorder
todos []models.Todo
)
func setup() {
todoController = *NewTodoController(services.NewTodoService())
recorder = httptest.NewRecorder()
todos = []models.Todo{
{
ID: 0,
Todo: "Buy milk",
Completed: false,
},
{
ID: 1,
Todo: "Buy cheese",
Completed: false,
},
{
ID: 2,
Todo: "Buy eggs",
Completed: false,
},
}
}
func TestGetById(t *testing.T) {
// Arrange
setup()
request := httptest.NewRequest(http.MethodGet, "/todo/1", nil)
var response models.Todo
// Act
todoController.GetById(recorder, request)
result := recorder.Result()
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
err = json.Unmarshal(data, &response)
// Assert
if err != nil {
t.Errorf("Expected error to be nil but got %v", err)
}
assert.Equal(t, result.StatusCode, http.StatusOK, "Response should have been 200 Ok")
assert.Equal(t, response, todos[1], "Response did not match the expected result")
}
向 /todo/1
发送请求时,mux 似乎无法检索 Id,因此它最终会返回 BadRequest 错误。
这是此回购的 link:https://github.com/Je12emy/rest_boiler
Mux 提供了两种注入请求参数的方法 - SetURLVars
帮助器和使用 mux.Router
包装器而不是直接调用处理程序。
SetURLVars 完全按照您的意愿行事 - 将否则无法访问的参数注入 HTTP 请求。
这个方法很简单,但是有一个问题。使用的 URL 和注入的参数不同步。
None 禁止开发者编写此代码:
// we use 2 in request path
request := httptest.NewRequest(http.MethodGet, "/todo/2", nil)
// and we use 1 in request param
request = SetURLVars(request, map[string]string{"id":"1"})
这不是很干净的测试实践。
我们不测试路由中的 var 名称是否正确。我们可以在路由器中使用 item_id
而不是 id
并且测试没有捕捉到它。
不仅如此,我们还可以在路由器定义中使用错误的路径并映射不同的处理程序。如果我们犯了这个错误,客户可以删除 order
而不是 todo
项。
如果我们在测试中使用我们的生产路由器,就可以解决这个问题。
假设是我们的生产代码:
func InitRouter(t TodoController) http.handler
r := mux.NewRouter()
r.HandleFunc("/todo/{id}", t.GetById).Methods(http.MethodGet)
return r
在测试中,我们可以通过我们在InitRouter
函数中创建的路由器来测试GetById
:
func TestGetById(t *testing.T) {
// Arrange
setup()
request := httptest.NewRequest(http.MethodGet, "/todo/1", nil)
var response models.Todo
// added setup
sut := InitRouter(todoController)
// Act
// changed act - calling GetById through production router
sut.ServeHTTP(recorder, request)
// no chnages after that
result := recorder.Result()
defer result.Body.Close()
...
}