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

  • go version: 1.23.2
  • gin version (or commit ref): 1.10.0
  • operating system: Ubuntu 22.04

Comment From: JimChenWYU

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

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

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

Comment From: ksw2000

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.