【问题标题】:How to test reverse proxy with martini in go如何在 go 中使用 martini 测试反向代理
【发布时间】:2016-03-02 07:58:12
【问题描述】:

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

【问题讨论】:

  • go test -test.run="^TestReverseProxy$" 你的代码对我有用。您的文件是否以xxx_test.go 命名?否则会失败。
  • 这里可以重现

标签: go reverse-proxy martini


【解决方案1】:

首先,请注意,martini 框架不再像他们的README 中所说的那样维护。

然后,关于您的问题,这是因为 Martini 做了一些对我来说看起来很糟糕的事情:它需要一个 http.ResponseWriter 并假设它也是一个 http.CloseNotifier,但绝对不能保证这一点。他们应该采用一个自定义界面来包装它们,就像这样:

type ResponseWriterCloseNotifier interface {
    http.ResponseWriter
    http.CloseNotifier
}

您可以在他们的源代码中看到他们在自己的测试中遇到了同样的问题,并使用了一些解决方法:https://github.com/go-martini/martini/commit/063dfcd8b0f64f4e2c97f0bc27fa422969baa23b#L13

这是一些用它制作的工作代码:

package main

import (
    "net/http"
    "net/http/httptest"
    "net/http/httputil"
    "net/url"
    "testing"

    "github.com/go-martini/martini"
    "github.com/stretchr/testify/assert"
)

type closeNotifyingRecorder struct {
    *httptest.ResponseRecorder
    closed chan bool
}

func newCloseNotifyingRecorder() *closeNotifyingRecorder {
    return &closeNotifyingRecorder{
        httptest.NewRecorder(),
        make(chan bool, 1),
    }
}

func (c *closeNotifyingRecorder) close() {
    c.closed <- true
}

func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
    return c.closed
}

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 := newCloseNotifyingRecorder()
    m.ServeHTTP(res, req)

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

【讨论】:

  • 谢谢,我在其他站点找到了这个解决方案,但在我的机器上得到了panic: runtime error: invalid memory address or nil pointer dereference... > 不再维护 是的,我知道。我将替换为任何其他框架。
  • 好像是go1.5.1 darwin/amd64的问题... Ubuntu 14.04没问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-26
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 2023-03-16
  • 2014-06-05
  • 2018-02-22
相关资源
最近更新 更多