go - 有没有办法删除响应编写器中的数据?

标签 go

我正在为一个 elasticsearch 中间件编写测试,我在其中使用一个函数来构建测试服务器,我在其中为每个测试传递配置结构的一部分,并在处理函数中迭代它们并将预期的响应写入回复作者。这是我的职责。

func newMockClient(url string) (*elasticsearch, error) {
    client, err := elastic.NewSimpleClient(elastic.SetURL(url))
    if err != nil {
        return nil, fmt.Errorf("error while initializing elastic client: %v", err)
    }
    es := &elasticsearch{
        url:    url,
        client: client,
    }
    return es, nil
}

type ServerSetup struct {
    Method, Path, Body, Response string
    HTTPStatus                   int
}

func buildTestServer(t *testing.T, setups []*ServerSetup) *httptest.Server {
    handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        requestBytes, _ := ioutil.ReadAll(r.Body)
        requestBody := string(requestBytes)

        matched := false
        for _, setup := range setups {
            if r.Method == setup.Method && r.URL.EscapedPath() == setup.Path {
                matched = true
                if setup.HTTPStatus == 0 {
                    w.WriteHeader(http.StatusOK)
                } else {
                    w.WriteHeader(setup.HTTPStatus)
                }
                _, err := w.Write([]byte(setup.Response))
                if err != nil {
                    t.Fatalf("Unable to write test server response: %v", err)
                }
            }
        }

        if !matched {
            t.Fatalf("No requests matched setup. Got method %s, Path %s, body %s", r.Method, r.URL.EscapedPath(), requestBody)
        }
    })

    return httptest.NewServer(handlerFunc)
}

它是从 github.com/github/vulcanizer 复制的。当我使用它运行单个测试时,它工作正常。例如这个测试

func TestCreateIndex(t *testing.T) {
    setup := &ServerSetup{
        Method:   "PUT",
        Path:     "/test",
        Response: `{"acknowledged": true, "shards_acknowledged": true, "index": "test"}`,
    }

    ts := buildTestServer(t, []*ServerSetup{setup})

    es, _ := newMockClient(ts.URL)

    err := es.createIndex(context.Background(), "test", nil)
    if err != nil {
        t.Fatalf("Index creation failed with error: %v\n", err)
    }

}

但是当我尝试在像这样的单个测试中检查不同的行为时,我得到一个错误 http: multiple response.WriteHeader calls

func TestDeleteIndex(t *testing.T) {
    setup := &ServerSetup{
        Method:   "DELETE",
        Path:     "/test",
        Response: `{"acknowledged": true}`,
    }

    errSetup := &ServerSetup{
        Method:   "DELETE",
        Path:     "/test",
        Response: `{"acknowledged": false}`,
    }

    ctx := context.Background()

    ts := buildTestServer(t, []*ServerSetup{setup, errSetup})
    defer ts.Close()

    es, _ := newMockClient(ts.URL)

    err := es.deleteIndex(ctx, "test")
    if err != nil {
        t.Fatalf("Index creation failed with error: %v\n", err)
    }

    err = es.deleteIndex(ctx, "test")
    if err == nil {
        t.Fatal("Expected error but not found")
    }
}

我猜这是因为当我第二次运行 deleteIndex 时它再次对服务器执行 ping 操作,但响应编写器已经被写入,因此它无法向其写入任何其他内容。

无论如何我可以在我的处理程序函数的开头进行检查,比如

handlerFunc := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    if w != nil{
        // clear data in response writer
    }

// .........



}

最佳答案

我不认为您正在做的是测试功能的正确方法。您需要将测试分离到测试用例以检查不同的行为:

func Test_DeleteIndex(t *testing.T) {
    t.Run("Should be ok with correct setup", func(t *testing.T) {
        setup := &ServerSetup{
            Method:   "DELETE",
            Path:     "/test",
            Response: `{"acknowledged": true}`,
        }
        ctx := context.Background()
        ts := buildTestServer(t, []*ServerSetup{setup})
        defer ts.Close()
        es, _ := newMockClient(ts.URL)
        err := es.deleteIndex(ctx, "test")
        require.NoError(t, err)
    })

    t.Run("Shouldn't be ok with wrong setup", func(t *testing.T) {
        setup := &ServerSetup{
            Method:   "DELETE",
            Path:     "/test",
            Response: `{"acknowledged": false}`,
        }
        ctx := context.Background()
        ts := buildTestServer(t, []*ServerSetup{setup})
        defer ts.Close()
        es, _ := newMockClient(ts.URL)
        err := es.deleteIndex(ctx, "test")
        require.Error(t, err)
    })
}

关于go - 有没有办法删除响应编写器中的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55091006/

相关文章:

Go 的全局变量和 slice 范围

sql - 如何在 GORM 中动态设置 where 子句

go - 关于接口(interface)的方法实现

go - go-Cobra PersistentFlags 和 Flags 有什么区别?

Gorilla Mux 和 GORM 失败

从父函数返回子类型

mysql - 使用 GoLang 从 MySql 数据库将图像 (blob/jpeg) 转换为 html

go - 以下哪些是 Go 中用于控制循环的有效关键字?

go - 与多个包共享全局定义的 db conn

go - Go 中对 Google API 的无人值守授权