重置 Golang 中的 HTTP 处理程序以进行单元测试

huangapple go评论88阅读模式
英文:

Resetting http handlers in golang for unit testing

问题

我正在测试一个使用Go语言编写的HTTP服务器,除了一个令人讨厌的问题外,一切都很顺利。

在配置服务器之前,我使用http.Handle("/", myrouter)注册了一个处理程序,然后在执行http.ListenAndServe之前,出现了以下问题:

> panic: http: multiple registrations for / [recovered]

我希望在每个测试中都在一个干净的环境中运行,但是我找不到一种方法来清除http.DefaultServeMux,是否有一种方便的方法可以通过“nulling”某些内容或重新配置测试环境,以便每个测试都在一个新的环境中执行?


编辑:
为了提供一些上下文,如要求的,我在这里发布一些代码和我想编写的测试,但是我必须明确一点,我对这里的实现选择甚至不确定(我认为我会以稍微不同的方式配置服务器,但这不是我的代码)。

package httpserver

import (
	"github.com/gorilla/mux"
	"github.com/private/private/httpserver/rpchandler"
	"net/http"
)

type HTTPServer struct {
	router *mux.Router
	port   int
}

// Config is used to override the default port of the http server.
type Config struct {
	Port *int
}

func NewHTTPServer(config *Config) (*HTTPServer, error) {
	hs := &HTTPServer{
		port: 80,
	}

	// Overwrite default port if passed.
	if config != nil && config.Port != nil {
		hs.port = *config.Port
	}

	err := hs.router = mux.NewRouter().StrictSlash(false)
	if err != nil {
		return nil, err
	}
    // 其他mux路由器配置...

	http.Handle("/", hs.router)

	return hs, nil
}

现在,我想编写的测试非常简单,例如:

func TestThatServerIsInitializedWithDefaultPort(t *testing.T) {
	sut, _ := NewHTTPServer(nil)

	if sut.port != 80 {
		t.Fatal("未配置默认端口")
	}

}

func TestThatServerDefaultPortIsOverriddenWithConfig(t *testing.T) {
	mockPort := 8080

	c := Config{
		Port: &mockPort,
	}

	sut, _ := NewHTTPServer(&c)
	if sut.port != 8080 {
		t.Fatal("端口未被配置为传入的配置值")
	}

}

然而,由于我在http上调用了两次处理绑定,所以会出现panic。

英文:

I'm testing an http server in golang and everything seems pretty smooth except for one annoying thing.

At some point, when I'm configuring the server, before performing a http.ListenAndServe I register an handler with http.Handle("/", myrouter) , the problem is that on the following test, when the configuration method gets called again, I receive the following panic:

> panic: http: multiple registrations for / [recovered]

I'd like to run each test in a clean environment, but haven't found a way to tear down http.DefaultServeMux, is there a convenient way for doing this by either "nulling" something or re-configuring the test environment so every test is executed on a fresh environment ?


Edit:
To give some context, as asked, I post here some code and the test I wanted to write, I have to be clear tough on the fact that I'm not even sure on the implementation choices made here (I think I would have configured the server in a slightly different way, but the code's not mine).

package httpserver

import (
	"github.com/gorilla/mux"
	"github.com/private/private/httpserver/rpchandler"
	"net/http"
)

type HTTPServer struct {
	router *mux.Router
	port   int
}

// Config is used to override the default port of the http server.
type Config struct {
	Port *int
}

func NewHTTPServer(config *Config) (*HTTPServer, error) {
	hs := &HTTPServer{
		port: 80,
	}

	// Overwrite default port if passed.
	if config != nil && config.Port != nil {
		hs.port = *config.Port
	}

	err := hs.router = mux.NewRouter().StrictSlash(false)
	if err != nil {
		return nil, err
	}
    // other mux router configs here...

	http.Handle("/", hs.router)

	return hs, nil
}

Now, the tests I wanted to write were quite simple, like:

func TestThatServerIsInitializedWithDefaultPort(t *testing.T) {
	sut, _ := NewHTTPServer(nil)

	if sut.port != 80 {
		t.Fatal("default port not configured")
	}

}

func TestThatServerDefaultPortIsOverriddenWithConfig(t *testing.T) {
	mockPort := 8080

	c := Config{
		Port: &mockPort,
	}

	sut, _ := NewHTTPServer(&c)
	if sut.port != 8080 {
		t.Fatal("the port has not been overridden with the one passed in configuration")
	}

}

However, since I call the handle binding on http twice, I get the panic.

答案1

得分: 5

我认为我找到了一个解决方案:基本上,在每次测试之后,我使用http.DefaultServeMux = new(http.ServeMux)重新初始化http.DefaultServeMux
不过,我还不确定这是否是一种干净的解决方法。

我想请你给我一些提示,或指出我在这里使用的一些不良实践,因为我对这门语言和后端开发都还很陌生。
我认为上面显示的HTTP服务器配置中可能存在一些代码异味,如果你指出来,我可以向我的团队明确,并找到一个更好的解决方案。

英文:

I think I've found a solution: basically after each test I reinitialize http.DefaultServeMux with http.DefaultServeMux = new(http.ServeMux)
I'm still not sure this is a clean way to workaround the problem tough.

I kindly ask you to give me any hints or point me some bad practices used here, since I'm quite new to the language and to backend development in general.
I think there might be some code smell in the configuration of the HTTP Server shown above, if you point it out I might make it clear to the rest of my team and work a better solution out.

答案2

得分: 0

我认为你应该考虑使用httptest包。它提供了可以在每次测试时重新启动的服务器。

英文:

I think you should look at using the httptest pkg. It has servers that you can start fresh every test.

huangapple
  • 本文由 发表于 2016年11月24日 20:31:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/40786526.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定