gin-gonic / gin

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
https://gin-gonic.com/
MIT License
79.11k stars 8.03k forks source link

ctx.Status() does not affect httptest.ResponseRecorder while ctx.JSON() does #4071

Open cardillomarcelo opened 1 month ago

cardillomarcelo commented 1 month ago

Description

ctx.Status() does not affect httptest.ResponseRecorder while ctx.JSON() does

How to reproduce

package main

import (
    "fmt"
    "github.com/gin-gonic/gin"
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestName(t *testing.T) {
    recorder := httptest.NewRecorder()

    c, _ := gin.CreateTestContext(recorder)

    changeResponseCode(c)

    fmt.Println(recorder.Code)
}

func changeResponseCode(ctx *gin.Context) {
    ctx.Status(http.StatusNoContent)
}

Expectations

Should print 204

Actual result

Prints 200

Environment

JimChenWYU commented 1 month ago
image image

c.Status(204) do not change the recorder.status but change responseWriter.status

image
ksw2000 commented 1 week ago

It seems that ctx.Status() In the function changeResponseCode changes the Writer in ctx but doesn't change the recorder. That is to say, you can fetch the status code by c.Writer.Status()

func TestName(t *testing.T) {
    recorder := httptest.NewRecorder()

    c, _ := gin.CreateTestContext(recorder)

    changeResponseCode(c)

    fmt.Println(c.Writer.Status())  // 204
    fmt.Println(recorder.Code)  // 200
}

Besides, I found a related unit test in response_writer_test.go

https://github.com/gin-gonic/gin/blob/c8a3adc65703d8958265c07689662e54f037038c/response_writer_test.go#L54-L67

func TestResponseWriterWriteHeader(t *testing.T) {
    testWriter := httptest.NewRecorder()
    writer := &responseWriter{}
    writer.reset(testWriter)
    w := ResponseWriter(writer)

    w.WriteHeader(http.StatusMultipleChoices)
    assert.False(t, w.Written())
    assert.Equal(t, http.StatusMultipleChoices, w.Status())
    assert.NotEqual(t, http.StatusMultipleChoices, testWriter.Code)  // ← WHY ?

    w.WriteHeader(-1)
    assert.Equal(t, http.StatusMultipleChoices, w.Status())
}

I'm not sure why it was designed so that the original testWriter does not change along with it.