英文:
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%的覆盖率。请帮忙!谢谢
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
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
函数可以返回两种类型的错误。
UnsupportedTypeError
(例如:通道、复杂和函数值)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.
UnsupportedTypeError
(ex: channel, complex, and function values)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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论