Golang 单元测试中的问题:简单错误。

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

Golang Issue with Unit Testing for simple error

问题

我正在尝试测试一个内部存在错误的函数,名为ResponseJson。该函数不返回错误,但会发送一个响应的 JSON。以下是该函数的代码:

func ResponseJson(w http.ResponseWriter, Code int, Message string) {
	jsonStatus := struct {
		Code    int    `json:"code"`
		Message string `json:"message"`
	}{
		Message: Message,
		Code:    Code,
	}

	bs, err := json.Marshal(jsonStatus)

	if err != nil {
		log.Println("Error in Marshal JSON in ResponseJson:", err)
		str := "Internal Server Error. Please contact the System Administrator."
		io.WriteString(w, str)
		return
	} else {
		io.WriteString(w, string(bs))
		return
	}

}

以下是我的单元测试代码,它创建了一个模拟的 ResponseWriter,并且能够成功测试没有错误的情况下的写入响应 JSON。由于 ResponseJson() 函数没有返回错误类型,我该如何在 Test_ResponseJson 函数中测试它呢?

func Test_ResponseJson(t *testing.T) {
	responseJsonTests := []struct {
		testName             string
		code                 int
		message              string
		expectedJsonResponse string
	}{
		{"Successful Login", http.StatusOK, "Successfully Logged In!", `{"code":200,"message":"Successfully Logged In!"}`},
		{"Existing username", http.StatusBadRequest, "Username already exists. Please try again.", `{"code":400,"message":"Username already exists. Please try again."}`},
	}

	for _, e := range responseJsonTests {
		// 创建一个模拟的 ResponseWriter
		w := httptest.NewRecorder()

		ResponseJson(w, e.code, e.message)

		// 将响应体读取为字符串
		body, _ := io.ReadAll(w.Result().Body)
		actual := string(body)

		expected := e.expectedJsonResponse
		if actual != expected {
			t.Errorf("%s: expected %s but got %s", e.testName, e.expectedJsonResponse, actual)
		}
	}
}

此外,我创建了一个函数,用于生成 log.Println() 内置函数的实际日志输出。我知道 log.Println() 函数是一个内置函数,很不可能出错。然而,我想在我的单元测试中实现100%的覆盖率。请帮忙!谢谢 Golang 单元测试中的问题:简单错误。

func GenerateLogOutput(message string, errorMessage string) string {
	// 创建一个新的 bytes.Buffer 来捕获日志输出
	var buf bytes.Buffer

	// 将日志输出重定向到一个不同的目标,设置为缓冲区
	// 默认情况下,日志消息会被写入标准错误流 os.Stderr
	log.SetOutput(&buf)

	// 生成一个错误
	err := errors.New(errorMessage)

	w := httptest.NewRecorder()

	// 调用函数
	InternalServerError(w, message, err)
	actualOutput := buf.String()

	return actualOutput
}

以上是你要翻译的内容。

英文:

I am having trouble trying to test this function with an error inside. The following is my ResponseJson function which does not return an error but sends a response json.

func ResponseJson(w http.ResponseWriter, Code int, Message string) {
	jsonStatus := struct {
		Code int `json:"code"`
		Message string `json:"message"`
	}{
		Message: Message,
		Code: Code,
	}

	bs, err := json.Marshal(jsonStatus);

	if err != nil {
		log.Println("Error in Marshal JSON in ResponseJson: ", err)
		str := "Internal Server Error. Please contact the System Administrator."
		io.WriteString(w, str);
		return 
	} else {
		io.WriteString(w, string(bs));
		return
	}
	
}

The following is my unit testing code which creates a mock ResponseWriter and it is able to successfully test the writer response json for cases with no errors. Since I am not returning an error type in ResponseJson() function, how do I test it inside the Test_ResponseJson function as shown below?

func Test_ResponseJson(t *testing.T) {
	responseJsonTests := []struct {
		testName string
		code int
		message string
		expectedJsonResponse string
	} {
		{"Successful Login", http.StatusOK, "Successfully Logged In!", `{"code":200,"message":"Successfully Logged In!"}`},
		{"Existing username", http.StatusBadRequest, "Username already exists. Please try again.", `{"code":400,"message":"Username already exists. Please try again."}`},
	}

	for _, e := range responseJsonTests {
		// Creating a mock ResponseWriter
		w := httptest.NewRecorder()

		ResponseJson(w, e.code, e.message)

		// Read the response body as a string
		body, _ := io.ReadAll(w.Result().Body)
		actual := string(body)

		expected := e.expectedJsonResponse
		if actual != expected {
			t.Errorf("%s: expected %s but got %s", e.testName, e.expectedJsonResponse, actual)
		}
	}
}

Also, I have created a function which generates an actual log output for log.Println() built-in function. I am aware that the log.Println() function is a built-in function and it is highly unlikely to fail. However, I want to achieve 100% coverage in my unit testing. Please help! Thank you Golang 单元测试中的问题:简单错误。

func GenerateLogOutput(message string, errorMessage string) string {
	// Create a new bytes.Buffer to capture the log output
	var buf bytes.Buffer

	// Redirect log output to a different destination set as a buffer
	// By default, log message are written to the standard error stream os.Stderr
	log.SetOutput(&buf)

	// Generate an error
	err := errors.New(errorMessage)

	w := httptest.NewRecorder()

	// Calling the function
	InternalServerError(w, message, err)
	actualOutput := buf.String()

	return actualOutput
}

答案1

得分: 1

简单来说,我们可以编写一个针对ResponseJson函数的测试用例,如下所示。

func Test_ResponseJson(t *testing.T) {
	tests := []struct {
		Code        int
		Message     string
		ExpectedStr string
	}{
		{
			Code:        1,
			Message:     "sample message",
			ExpectedStr: `{"code":1,"message":"sample message"}`,
		},
	}
	for _, test := range tests {
		w := httptest.NewRecorder()

		ResponseJson(w, test.Code, test.Message)

		res := w.Result()
		data, err := ioutil.ReadAll(res.Body)
		res.Body.Close()

		actualStr := string(data)

		assert.Nil(t, err, "Invalid test data")
		assert.Equal(t, actualStr, test.ExpectedStr)
	}
}

我们无法从bs, err := json.Marshal(jsonStatus)中获得错误。json.Marshal函数可以返回两种类型的错误。

  1. UnsupportedTypeError(例如:通道、复杂和函数值)
  2. UnsupportedValueError(例如:循环数据结构)

我们无法解析值以生成上述任何一种错误。我们正在解析具有支持的值和支持的类型的结构体。因此,我们无法编写具有100%覆盖率的测试。

英文:

Simply, We can write a test case for the ResponseJson function as below.

 func Test_ResponseJson(t *testing.T) {
	tests := []struct {
		Code        int
		Message     string
		ExpectedStr string
	}{
		{
			Code:        1,
			Message:     "sample message",
			ExpectedStr: "{\"code\":1,\"message\":\"sample message\"}",
		},
	}
	for _, test := range tests {
		w := httptest.NewRecorder()

		ResponseJson(w, test.Code, test.Message)

		res := w.Result()
		data, err := ioutil.ReadAll(res.Body)
		res.Body.Close()

		actualStr := string(data)

		assert.Nil(t, err, "Invalid test data")
		assert.Equal(t, actualStr, test.ExpectedStr)
	}
}

We cannot get an error from bs, err := json.Marshal(jsonStatus). The json.Marshal function can return two types of errors.

  1. UnsupportedTypeError (ex: channel, complex, and function values)
  2. UnsupportedValueError (ex: cyclic data structures)

We cannot parse values to generate either one of the above errors. We are parsing a struct with supported values and supported types. Therefore, we cannot write tests with 100% coverage.

huangapple
  • 本文由 发表于 2023年3月12日 10:02:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75710686.html
匿名

发表评论

匿名网友

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

确定