Go语言 如何对服务器发送的事件进行单元测试?

iih3973s  于 2023-04-27  发布在  Go
关注(0)|答案(3)|浏览(120)

我想在单元测试中读取服务器发送事件的响应。我想避免时间。不惜一切代价睡觉。
目前我读到的响应w http.ResponseRecorder是这样的:

func (f *fixture) readResponse(t *testing.T) []byte {
    t.Helper()

    byteCh := make(chan []byte)
    timeout := time.After(100 * time.Millisecond)

    go func() {
        for len(f.w.Body.Bytes()) == 0 {
        }

        byteCh <- f.w.Body.Bytes()
    }()

    select {
    case b := <-byteCh:
        return b
    case <-timeout:
        t.Error("no response received")
        return nil
    }
}

我等着一个事件被写成这样:

for len(f.w.Body.Bytes()) == 0 {
}

如果没有for或time.Sleep,还有什么可供选择的?

tv6aics1

tv6aics11#

io.ReadAll就足够了。

func (f *fixture) readResponse(t *testing.T) []byte {
    t.Helper()

    byteCh := make(chan []byte)
    timeout := time.After(100 * time.Millisecond)

    go func() {
        body, err := io.ReadAll(f.w.Body)
        if err != nil {
            // error handler
        }

        byteCh <- body
    }()

    select {
    case b := <-byteCh:
        return b
    case <-timeout:
        t.Error("no response received")
        return nil
    }
}
5us2dqdw

5us2dqdw2#

如何 Package httptest.ResponseRecorder并覆盖WriteWriteString方法?

package m

import (
    "fmt"
    "net/http"
    "net/http/httptest"
    "sync"
    "testing"
    "time"
)

type ServerEventRecorder struct {
    httptest.ResponseRecorder
    C chan []byte
}

func NewRecorder() *ServerEventRecorder {
    return &ServerEventRecorder{
        ResponseRecorder: *httptest.NewRecorder(),
        C:                make(chan []byte, 2),
    }
}

func (rw *ServerEventRecorder) Write(buf []byte) (int, error) {
    rw.C <- buf
    return rw.ResponseRecorder.Write(buf)
}

func (rw *ServerEventRecorder) WriteString(str string) (int, error) {
    rw.C <- []byte(str)
    return rw.ResponseRecorder.WriteString(str)
}

func (rw *ServerEventRecorder) Close() {
    close(rw.C)
}

func TestXxx(t *testing.T) {
    handler := func(w http.ResponseWriter, r *http.Request) {
        for i := 0; i < 5; i++ {
            i := i
            time.Sleep(100 * time.Millisecond)
            fmt.Fprintf(w, "data: some text - %d", i)
        }
    }

    req := httptest.NewRequest("GET", "http://example.com/foo", nil)
    w := NewRecorder()

    var wg sync.WaitGroup
    wg.Add(1)
    go func() {
        for buf := range w.C {
            t.Logf("%s\n", buf)
        }
        wg.Done()
    }()

    handler(w, req)
    w.Close()
    wg.Wait()
}
mftmpeh8

mftmpeh83#

我还在学围棋,但这样的东西有用吗?

type fixture struct {
    w      *httptest.ResponseRecorder
    signal chan struct{}
    mu     sync.Mutex
}

func newFixture() *fixture {
    return &fixture{
        w:      httptest.NewRecorder(),
        signal: make(chan struct{}),
    }
}

func (f *fixture) writeResponse(data []byte) {
    f.mu.Lock()
    f.w.Body = bytes.NewBuffer(data)
    f.mu.Unlock()

    // Signal that the response is ready
    close(f.signal)
}

func (f *fixture) readResponse(t *testing.T) []byte {
    t.Helper()

    timeout := time.After(100 * time.Millisecond)

    select {
    case <-f.signal:
        f.mu.Lock()
        b := f.w.Body.Bytes()
        f.mu.Unlock()
        return b
    case <-timeout:
        t.Error("no response received")
        return nil
    }
}

信号通道和互斥体被添加到fixture结构中。因此writeResponse设置响应体,并通过关闭信号通道发出就绪信号。readResponse函数在阅读响应体之前等待信号。
我认为这将避免你的for循环和需要睡眠。

相关问题