如何在 go 中使用马提尼测试反向代理

我正在为在 go 中作为反向代理工作的 martini 应用程序编写测试代码,并想使用 测试它httptest.ResponseRecorder,但出现以下错误。


[martini] PANIC: interface conversion: *httptest.ResponseRecorder is not http.CloseNotifier: missing method CloseNotify

httptest.ResponseRecorder 没有方法 CloseNotify()


我应该如何测试?


package main


import (

        "github.com/go-martini/martini"

        "github.com/stretchr/testify/assert"

        "net/http"

        "net/http/httptest"

        "net/http/httputil"

        "net/url"

        "testing"

)


func TestReverseProxy(t *testing.T) {

        // Mock backend

        backendResponse := "I am the backend"

        backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

                w.Write([]byte(backendResponse))

        }))

        defer backend.Close()

        backendURL, _ := url.Parse(backend.URL)


        // Frontend

        m := martini.Classic()

        m.Get("/", func(w http.ResponseWriter, r *http.Request) {

                proxy := httputil.NewSingleHostReverseProxy(backendURL)

                proxy.ServeHTTP(w, r)

        })


        // Testing

        req, _ := http.NewRequest("GET", "/", nil)

        res := httptest.NewRecorder()

        m.ServeHTTP(res, req)


        assert.Equal(t, 200, res.Code, "should be equal")

}


一只萌萌小番薯
浏览 152回答 1
1回答

慕森王

首先,请注意 martini 框架不再像他们的README 中所说的那样维护。然后,关于您的问题,这是因为 Martini 做了一些对我来说看起来很糟糕的事情:它需要一个http.ResponseWriter并假设它也是一个http.CloseNotifier,而绝对不能保证这一点。他们应该采用一个自定义界面来包装它们,如下所示:type ResponseWriterCloseNotifier interface {&nbsp; &nbsp; http.ResponseWriter&nbsp; &nbsp; http.CloseNotifier}您可以在他们的源代码中看到他们在自己的测试中遇到了同样的问题,并使用了一些解决方法:https : //github.com/go-martini/martini/commit/063dfcd8b0f64f4e2c97f0bc27fa422969baa23b#L13这是一些用它制作的工作代码:package mainimport (&nbsp; &nbsp; "net/http"&nbsp; &nbsp; "net/http/httptest"&nbsp; &nbsp; "net/http/httputil"&nbsp; &nbsp; "net/url"&nbsp; &nbsp; "testing"&nbsp; &nbsp; "github.com/go-martini/martini"&nbsp; &nbsp; "github.com/stretchr/testify/assert")type closeNotifyingRecorder struct {&nbsp; &nbsp; *httptest.ResponseRecorder&nbsp; &nbsp; closed chan bool}func newCloseNotifyingRecorder() *closeNotifyingRecorder {&nbsp; &nbsp; return &closeNotifyingRecorder{&nbsp; &nbsp; &nbsp; &nbsp; httptest.NewRecorder(),&nbsp; &nbsp; &nbsp; &nbsp; make(chan bool, 1),&nbsp; &nbsp; }}func (c *closeNotifyingRecorder) close() {&nbsp; &nbsp; c.closed <- true}func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {&nbsp; &nbsp; return c.closed}func TestReverseProxy(t *testing.T) {&nbsp; &nbsp; // Mock backend&nbsp; &nbsp; backendResponse := "I am the backend"&nbsp; &nbsp; backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; &nbsp; &nbsp; w.Write([]byte(backendResponse))&nbsp; &nbsp; }))&nbsp; &nbsp; defer backend.Close()&nbsp; &nbsp; backendURL, _ := url.Parse(backend.URL)&nbsp; &nbsp; // Frontend&nbsp; &nbsp; m := martini.Classic()&nbsp; &nbsp; m.Get("/", func(w http.ResponseWriter, r *http.Request) {&nbsp; &nbsp; &nbsp; &nbsp; proxy := httputil.NewSingleHostReverseProxy(backendURL)&nbsp; &nbsp; &nbsp; &nbsp; proxy.ServeHTTP(w, r)&nbsp; &nbsp; })&nbsp; &nbsp; // Testing&nbsp; &nbsp; req, _ := http.NewRequest("GET", "/", nil)&nbsp; &nbsp; res := newCloseNotifyingRecorder()&nbsp; &nbsp; m.ServeHTTP(res, req)&nbsp; &nbsp; assert.Equal(t, 200, res.Code, "should be equal")}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go