首页 > 解决方案 > 有没有办法擦除响应编写器中的数据?

问题描述

我正在为 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
    }

// .........



}

标签: go

解决方案


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

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)
    })
}

推荐阅读