英文:
How do I create a mock instance of http.ResponseWriter that returns an error on responseWriter.Write?
问题
我将所有与响应相关的Go代码移入了一个函数中:
import (
"encoding/json"
"net/http"
"github.com/rs/zerolog"
)
func WriteResponse(responseWriter http.ResponseWriter, responseBody any, httpStatusCode int) {
encodedResponseBody, err := json.Marshal(responseBody)
if err != nil {
// 调用日志记录器
apiResponse := NewErrorApiResponse() // 为HTTP 500响应创建一个结构体
encodedResponseBody, err = json.Marshal(apiResponse)
responseWriter.WriteHeader(http.StatusInternalServerError)
if err != nil {
// 调用日志记录器
return
}
_, err = responseWriter.Write(encodedResponseBody)
if err != nil {
// 调用日志记录器
}
return
}
responseWriter.WriteHeader(httpStatusCode)
_, err = responseWriter.Write(encodedResponseBody)
if err != nil {
// 调用日志记录器
}
}
并为以下情况创建了测试:
- 成功
- 错误 =>
json.Marshal()
失败,但responseWriter.Write()
没有失败
现在我还想为以下情况创建一个测试:
json.Marshal()
失败,它尝试创建一个错误响应,但responseWriter.Write()
也失败了,所以我们只能记录错误
所以基本上我从这里开始:
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestWriteResponse_NoResponseBody(testing *testing.T) {
// TODO 使用返回.Write()错误的模拟替代
responseWriter := httptest.NewRecorder()
responseBody := make(chan int)
WriteResponse(responseWriter, responseBody, http.StatusOK)
assert.Equal(testing, http.StatusInternalServerError, responseWriter.Code, fmt.Sprintf("期望状态码为%d,但得到%d", http.StatusInternalServerError, responseWriter.Code))
actualResponseBodyAsString := responseWriter.Body.String()
assert.Equal(testing, "", actualResponseBodyAsString, fmt.Sprintf("期望响应体为空,但得到'%s'", actualResponseBodyAsString))
}
但是测试失败,因为 responseWriter.Write()
正常工作。我该如何强制它返回一个错误,以便响应体为空?
英文:
I moved all the response related Go code into a function
import (
"encoding/json"
"net/http"
"github.com/rs/zerolog"
)
func WriteResponse(responseWriter http.ResponseWriter, responseBody any, httpStatusCode int) {
encodedResponseBody, err := json.Marshal(responseBody)
if err != nil {
// call logger
apiResponse := NewErrorApiResponse() // create a struct for HTTP 500 responses
encodedResponseBody, err = json.Marshal(apiResponse)
responseWriter.WriteHeader(http.StatusInternalServerError)
if err != nil {
// call logger
return
}
_, err = responseWriter.Write(encodedResponseBody)
if err != nil {
// call logger
}
return
}
responseWriter.WriteHeader(httpStatusCode)
_, err = responseWriter.Write(encodedResponseBody)
if err != nil {
// call logger
}
}
and created tests for the following cases
- Success
- Error =>
json.Marshal()
failed but notresponseWriter.Write()
now I also want to create a test for the following case
> json.Marshal()
failed, it tried to create an error response but responseWriter.Write()
too so we can only log the error
So basically I started with
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestWriteResponse_NoResponseBody(testing *testing.T) {
// TODO replace with mock returning error on .Write()
responseWriter := httptest.NewRecorder()
responseBody := make(chan int)
WriteResponse(responseWriter, responseBody, http.StatusOK)
assert.Equal(testing, http.StatusInternalServerError, responseWriter.Code, fmt.Sprintf("Expected status code %d, but got %d", http.StatusInternalServerError, responseWriter.Code))
actualResponseBodyAsString := responseWriter.Body.String()
assert.Equal(testing, "", actualResponseBodyAsString, fmt.Sprintf("Expected response body to be empty but got '%s'", actualResponseBodyAsString))
}
but the test fails because responseWriter.Write()
is working fine. How do I force it to return an error so the response body will be empty?
答案1
得分: 4
只需实现以下接口:
type ResponseWriter interface {
Header() Header
Write([]byte) (int, error)
WriteHeader(statusCode int)
}
所以可以这样实现:
type ErrorMockResponseWriter struct {
Body io.ReadCloser
Code int
}
func (e *ErrorMockResponseWriter) Header() http.Header {
return http.Header{}
}
func (e *ErrorMockResponseWriter) Write(data []byte) (int, error){
e.Body = io.NopCloser(bytes.NewReader(data))
return 0, fmt.Errorf("always errors")
}
func (e *ErrorMockResponseWriter) WriteHeader(statusCode int) {
e.Code = statusCode
}
func TestWriteResponse_NoResponseBody(testing *testing.T) {
// TODO replace with mock returning error on .Write()
responseWriter := ErrorMockResponseWriter()
responseBody := make(chan int)
WriteResponse(responseWriter, responseBody, http.StatusOK)
assert.Equal(testing, http.StatusInternalServerError, responseWriter.Code, fmt.Sprintf("Expected status code %d, but got %d", http.StatusInternalServerError, responseWriter.Code))
actualResponseBodyAsString := responseWriter.Body.String()
assert.Equal(testing, "", actualResponseBodyAsString, fmt.Sprintf("Expected response body to be empty but got '%s'", actualResponseBodyAsString))
}
英文:
Just implement the interface:
type ResponseWriter interface {
Header() Header
Write([]byte) (int, error)
WriteHeader(statusCode int)
}
so something like
type ErrorMockResponseWriter struct {
Body io.ReadCloser
Code int
}
func (e *ErrorMockResponseWriter) Header() http.Header {
return http.Header{}
}
func (e *ErrorMockResponseWriter) Write(data []byte) (int, error){
e.Body = io.NopCloser(bytes.NewReader(data))
return 0, fmt.Errorf("always errors")
}
func (e *ErrorMockResponseWriter) WriteHeader(statusCode int) {
e.Code = statusCode
}
func TestWriteResponse_NoResponseBody(testing *testing.T) {
// TODO replace with mock returning error on .Write()
responseWriter := ErrorMockResponseWriter()
responseBody := make(chan int)
WriteResponse(responseWriter, responseBody, http.StatusOK)
assert.Equal(testing, http.StatusInternalServerError, responseWriter.Code, fmt.Sprintf("Expected status code %d, but got %d", http.StatusInternalServerError, responseWriter.Code))
actualResponseBodyAsString := responseWriter.Body.String()
assert.Equal(testing, "", actualResponseBodyAsString, fmt.Sprintf("Expected response body to be empty but got '%s'", actualResponseBodyAsString))
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论