mux.Vars 无法从 httpTest 请求中检索 var

我正在为未来的项目编写一个简单的 rest 样板,我目前正在为我的控制器进行一些测试,我正在尝试通过它的 Id 检索待办事项,这/todo/{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/1mux 发送请求时无法检索 Id,因此它最终返回 BadRequest 错误。


这是此回购协议的链接:https ://github.com/Je12emy/rest_boiler


回首忆惘然
浏览 98回答 1
1回答

aluckdog

Mux 提供了两种注入请求参数的方法——SetURLVars帮助器和使用mux.Router包装器而不是直接调用处理程序。SetURLVars做的正是你想要的——将否则无法访问的参数注入到 HTTP 请求中。这种方法很简单,但有一个问题。使用的 URL 和注入的参数不同步。None 禁止开发人员编写此代码:// we use 2 in request pathrequest := httptest.NewRequest(http.MethodGet, "/todo/2", nil)// and we use 1 in request paramrequest = SetURLVars(request, map[string]string{"id":"1"})这不是很干净的测试实践。我们不测试路由中的 var 名称是否正确。我们可以item_id在 router 中使用而不是id并且测试没有捕获到它。不仅如此,我们还可以在路由器定义中使用错误的路径并映射不同的处理程序。如果我们犯了那个错误,客户可以删除order而不是项目。todo如果我们在测试中使用我们的生产路由器,这可以解决。假设这是我们的生产代码:func InitRouter(t TodoController) http.handler    r := mux.NewRouter()    r.HandleFunc("/todo/{id}", t.GetById).Methods(http.MethodGet)    return r在测试中,我们可以GetById通过我们在InitRouter函数中创建的路由器进行测试: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()    ...}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go