gpt4 book ai didi

unit-testing - 如何在 ReverseProxy 中测试 header ?

转载 作者:数据小太阳 更新时间:2023-10-29 03:20:14 25 4
gpt4 key购买 nike

我正在尝试对以下代码进行单元测试:

func(h *Handler)Forward(w http.ResponseWriter, r *http.Request) {

url, err := url.Parse("http://test.com")
if err != nil {
return
}

reverseProxy := &httputil.ReverseProxy{
Director: func(r *http.Request) {
r.URL.Host = url.Host
r.URL.Path = "/"
r.URL.Scheme = url.Scheme
r.Host = url.Host
r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
},
}


reverseProxy.ServeHTTP(w, r)
}

我不知道如何测试标题是否被 Director 函数修改。我们如何在 Go 中的反向代理中测试 header ?

最佳答案

1。将外部依赖项注入(inject)被测单元

我现在看到的最大问题是您转发到的 URL 是硬编码在您的函数中的。这使得单元测试变得非常困难。所以第一步是从函数中提取 URL。在不了解其余代码的情况下,Handler 似乎是执行此操作的好地方。简化:

type Handler struct {
backend *url.URL
}

func NewHandler() (*Handler, error) {
backend, err := url.Parse("http://test.com")
if err != nil {
return nil, err
}
return &Handler{backend}, nil
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
reverseProxy := &httputil.ReverseProxy{
Director: func(r *http.Request) {
r.URL.Host = h.backend.Host
r.URL.Path = "/"
r.URL.Scheme = h.backend.Scheme
r.Host = url.Host
r.Header.Set("X-Forwarded-Host", r.Header.Get("Host"))
},
}
reverseProxy.ServeHTTP(w, r)
}

请注意,我已将 Forward 重命名为 ServeHTTP 以简化此示例。

2。使用 httptest 进行实时处理程序测试

下一步是进行基本测试:

func TestHandler(t *testing.T) {
// 1. set-up a backend server
// 2. set-up a reverse proxy with the handler we are testing
// 3. call the reverse-proxy
// 4. check that the backend server received the correct header

}

让我们从填写简单的部分开始:

// set-up a backend server 
backendServer := httptest.NewServer(http.DefaultServeMux)
defer backendServer.Close()

backendURL, err := url.Parse(backendServer.URL)
if err != nil {
t.Fatal(err)
}

// set-up the reverse proxy
handler := &Handler{backend: backendURL} // <-- here we inject our own endpoint!
reverseProxy := httptest.NewServer(handler)
defer reverseProxy.Close()

reverseProxyURL, err := url.Parse(reverseProxy.URL)
if err != nil {
t.Fatal(err)
}

// call the reverse proxy
res, err := http.Get(reverseProxy.URL)
if err != nil {
t.Fatal(err)
}
// todo optional: assert properties of the response
_ = res


// check that the backend server received the correct header
// this comes next...

3。将测试服务器的结果传达给测试

现在我们需要的是一种将接收到的 header 传递给主测试的方法。由于我们的测试服务器可以使用任意处理程序,因此让我们扩展后端服务器的设置。

var (
mu sync.Mutex
header string
)

// create a backend server that checks the incoming headers
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
header = r.Header.Get("X-Forwarded-Host")
w.WriteHeader(http.StatusOK)
}))
defer backendServer.Close()

请注意我是如何使用互斥量的,因为处理程序将在不同的 go-routine 中运行。您也可以使用 channel 。

此时,我们可以实现我们的断言:

mu.Lock()
got := header
mu.Unlock()

// check that the header has been set
want := reverseProxyURL.Host
if got != want {
t.Errorf("GET %s gives header %s, got %s", reverseProxy.URL, want, got)
}

请注意,这仍然会失败,但这次是因为您的测试代码有误:-) r.Header.Get("Host") 应替换为 r.Host

附录:完整示例

package example

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

type Handler struct {
backend *url.URL
}

func NewHandler() (*Handler, error) {
backend, err := url.Parse("http://test.com")
if err != nil {
return nil, err
}
return &Handler{backend}, nil
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
reverseProxy := &httputil.ReverseProxy{
Director: func(r *http.Request) {
r.URL.Host = h.backend.Host
r.URL.Path = "/"
r.URL.Scheme = h.backend.Scheme
r.Header.Set("X-Forwarded-Host", r.Host)
r.Host = h.backend.Host
},
}
reverseProxy.ServeHTTP(w, r)
}

func TestHandler(t *testing.T) {
var (
mu sync.Mutex
header string
)

// create a backend server that checks the incoming headers
backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
defer mu.Unlock()
header = r.Header.Get("X-Forwarded-Host")
w.WriteHeader(http.StatusOK)
}))
defer backendServer.Close()

backendURL, err := url.Parse(backendServer.URL)
if err != nil {
t.Fatal(err)
}

// create a server for your reverse proxy
handler := &Handler{backend: backendURL}
reverseProxy := httptest.NewServer(handler)
defer reverseProxy.Close()

reverseProxyURL, err := url.Parse(reverseProxy.URL)
if err != nil {
t.Fatal(err)
}

// make a request to the reverse proxy
res, err := http.Get(reverseProxy.URL)
if err != nil {
t.Fatal(err)
}
// todo optional: assert properties of the response
_ = res

mu.Lock()
got := header
mu.Unlock()

// check that the header has been set
want := reverseProxyURL.Host
if got != want {
t.Errorf("GET %s gives header %s, got %s", reverseProxy.URL, want, got)
}
}

关于unit-testing - 如何在 ReverseProxy 中测试 header ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55179625/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com