如何在Golang语言中使用http.ResponseWriter和http.Request作为参数(单元测试)

huangapple go评论85阅读模式
英文:

How to use http.ResponseWriter and http.request as argument(Unit Testing) with Golang language

问题

我刚刚开始学习Golang和PostgreSQL。目前,我尝试为CreateTodo函数编写单元测试。

我的CreateTodo函数如下:

func CreateTodo(w http.ResponseWriter, r *http.Request) {
	CreateTodo := &models.Todo{}
	utils.ParseBody(r, CreateTodo)
	CreateTodoList := CreateTodo.CreateTodo()
	res, _ := json.Marshal(CreateTodoList)
	w.WriteHeader(http.StatusOK)
	w.Write(res)
}

我试图为这个函数编写单元测试...到目前为止,我写了一些代码,如下:

func TestCreateTodo(t *testing.T) {
	dbData := &models.Todo{
		Title:       "test-title-console-check",
		Description: "test-description-console-check",
		Condition:   true,
	}

	utils.ParseBody(r, dbData) // r应该是r *http.Request

	submittedTodo := dbData.CreateTodo()
	res, _ := json.Marshal(submittedTodo)
	r.WriteHeader(http.StatusOK) // r应该是r *http.Request
	r.Write(res)

	fmt.Println("res: ", res)
}

这是utils文件夹中的ParseBody函数:

func ParseBody(r *http.Request, x interface{}) {
	if body, err := ioutil.ReadAll(r.Body); err == nil {
		if err := json.Unmarshal([]byte(body), x); err != nil {
			return
		}
	}
}

在这里,我遇到了一个问题,即如何传递net/http(r *http.Request)。我不确定如何像参数一样传递这个函数...我尝试在TestCreateTodo(t *testing.T, r *http.Request)中接收它,但结果不如我所预期。

有没有办法对CreateTodo函数进行单元测试?

非常感谢你的帮助!

编辑1:

我尝试创建一个全局变量:

var readData *http.Request
var writeData http.ResponseWriter

并在函数中使用它。我将其设置为全局变量的原因是,我通常在类似w http.ResponseWriter, r *http.Request的函数中使用它,所以我认为我也可以将其用作全局变量。

所以我修改了我的代码如下:

var readData *http.Request
var writeData http.ResponseWriter

func TestCreateTodo(t *testing.T) {
	// w := httptest.NewRecorder()
	dbData := &models.Todo{
		Title:       "test-title-console-check",
		Description: "test-description-console-check",
		Condition:   true,
	}

	utils.ParseBody(readData, dbData)

	submittedTodo := dbData.CreateTodo()
	res, _ := json.Marshal(submittedTodo)
	writeData.WriteHeader(http.StatusOK)
	writeData.Write(res)

	fmt.Println("res: ", res)
}

但是我得到了这个错误:

如何在Golang语言中使用http.ResponseWriter和http.Request作为参数(单元测试)

英文:

I just getting started learning Golang and PostgreSQL. For now, I tried to make Unit testing for CreateTodo function.
My CreateTodo function is

func CreateTodo(w http.ResponseWriter, r *http.Request) {
	CreateTodo := &models.Todo{}
	utils.ParseBody(r, CreateTodo)
	CreateTodoList := CreateTodo.CreateTodo()
	res, _ := json.Marshal(CreateTodoList)
	w.WriteHeader(http.StatusOK)
	w.Write(res)
}

I tried to make Unit Test for this function... So far I wrote some codes like

func TestCreateTodo(t *testing.T) {
	dbData := &models.Todo{
		Title: "test-title-console-check",
		Description: "test-description-console-check",
		Condition: true,
	}

	utils.ParseBody(r, dbData) // r should be r *http.Request

	submittedTodo := dbData.CreateTodo()
	res, _ := json.Marshal(submittedTodo)
	r.WriteHeader(http.StatusOK) // r should be r *http.Request
	r.Write(res)

	fmt.Println("res: ", res)
}

This is ParseBodu function in utils folder

func ParseBody(r *http.Request, x interface{}) {
	if body, err := ioutil.ReadAll(r.Body); err == nil {
		if err := json.Unmarshal([]byte(body), x); err != nil {
			return
		}
	}
}

Here, I have a problem with passing net/http(r *http.Request). I am not sure how to pass this function like argument... I tried to receive it in TestCreateTodo(t *testing.T, r *http.Request) but not working what I expected.

Is there any way to unit test for CreateTodo function??

I really appreciate your help!

Edit 1]

I tried to make a global variable

var readData *http.Request
var writeData http.ResponseWriter

and using it in the function. The reason why I make it global variables is that I usually use it in the funcs like <w http.ResponseWriter, r *http.Request>, so I thought I can use as global vars too.

so I edit my code as

var readData *http.Request
var writeData http.ResponseWriter

func TestCreateTodo(t *testing.T) {
	// w := httptest.NewRecorder()
	dbData := &amp;models.Todo{
		Title: &quot;test-title-console-check&quot;,
		Description: &quot;test-description-console-check&quot;,
		Condition: true,
	}

	utils.ParseBody(readData, dbData)

	submittedTodo := dbData.CreateTodo()
	res, _ := json.Marshal(submittedTodo)
	writeData.WriteHeader(http.StatusOK)
	writeData.Write(res)

	fmt.Println(&quot;res: &quot;, res)
}

But I got this error
如何在Golang语言中使用http.ResponseWriter和http.Request作为参数(单元测试)

答案1

得分: 3

根据Volker的提醒,你需要创建一个HTTP请求。所以你缺少了这一行代码:

req, err := http.NewRequest("GET", <你的端点>, <你的请求体>)

根据Go的http包文档,请求体必须以字节流的形式传递。你可以使用bytes.Buffer来实现:

var body bytes.Buffer
err := json.NewEncoder(&body).Encode(dbData)

在发送请求之后,你需要初始化一个响应记录器并定义处理程序:

res := httptest.NewRecorder()
handler := http.HandlerFunc(<你的处理程序>)
handler.ServeHTTP(res, req)

然后你可以使用assert包来检查你的响应是否符合预期。

~ Zoe ~

英文:

As mentioned by Volker, you need to create an http request. So you are missing this line:

req, err := http.NewRequest(&quot;GET&quot;, &lt;your endpoint&gt;, &lt;your body&gt;)

As shown by the Go http package documentation, the body must be passed as a stream of bytes. You can use bytes.Buffer for this:

var body bytes.Buffer
err := json.NewEncoder(&amp;body).Encode(dbData)

After making your request, you need to initiate a response recorder and define the handler:

res := httptest.NewRecorder()
handler := http.HandlerFunc(&lt;your handler&gt;)
handler.ServeHTTP(res, req)

Then you can check if your response was as expected with the assert package.

~ Zoe ~

huangapple
  • 本文由 发表于 2022年2月25日 14:47:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/71262072.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定