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

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

Resetting http handlers in golang for unit testing

问题

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

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

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

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


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

  1. package httpserver
  2. import (
  3. "github.com/gorilla/mux"
  4. "github.com/private/private/httpserver/rpchandler"
  5. "net/http"
  6. )
  7. type HTTPServer struct {
  8. router *mux.Router
  9. port int
  10. }
  11. // Config is used to override the default port of the http server.
  12. type Config struct {
  13. Port *int
  14. }
  15. func NewHTTPServer(config *Config) (*HTTPServer, error) {
  16. hs := &HTTPServer{
  17. port: 80,
  18. }
  19. // Overwrite default port if passed.
  20. if config != nil && config.Port != nil {
  21. hs.port = *config.Port
  22. }
  23. err := hs.router = mux.NewRouter().StrictSlash(false)
  24. if err != nil {
  25. return nil, err
  26. }
  27. // 其他mux路由器配置...
  28. http.Handle("/", hs.router)
  29. return hs, nil
  30. }

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

  1. func TestThatServerIsInitializedWithDefaultPort(t *testing.T) {
  2. sut, _ := NewHTTPServer(nil)
  3. if sut.port != 80 {
  4. t.Fatal("未配置默认端口")
  5. }
  6. }
  7. func TestThatServerDefaultPortIsOverriddenWithConfig(t *testing.T) {
  8. mockPort := 8080
  9. c := Config{
  10. Port: &mockPort,
  11. }
  12. sut, _ := NewHTTPServer(&c)
  13. if sut.port != 8080 {
  14. t.Fatal("端口未被配置为传入的配置值")
  15. }
  16. }

然而,由于我在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).

  1. package httpserver
  2. import (
  3. "github.com/gorilla/mux"
  4. "github.com/private/private/httpserver/rpchandler"
  5. "net/http"
  6. )
  7. type HTTPServer struct {
  8. router *mux.Router
  9. port int
  10. }
  11. // Config is used to override the default port of the http server.
  12. type Config struct {
  13. Port *int
  14. }
  15. func NewHTTPServer(config *Config) (*HTTPServer, error) {
  16. hs := &HTTPServer{
  17. port: 80,
  18. }
  19. // Overwrite default port if passed.
  20. if config != nil && config.Port != nil {
  21. hs.port = *config.Port
  22. }
  23. err := hs.router = mux.NewRouter().StrictSlash(false)
  24. if err != nil {
  25. return nil, err
  26. }
  27. // other mux router configs here...
  28. http.Handle("/", hs.router)
  29. return hs, nil
  30. }

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

  1. func TestThatServerIsInitializedWithDefaultPort(t *testing.T) {
  2. sut, _ := NewHTTPServer(nil)
  3. if sut.port != 80 {
  4. t.Fatal("default port not configured")
  5. }
  6. }
  7. func TestThatServerDefaultPortIsOverriddenWithConfig(t *testing.T) {
  8. mockPort := 8080
  9. c := Config{
  10. Port: &mockPort,
  11. }
  12. sut, _ := NewHTTPServer(&c)
  13. if sut.port != 8080 {
  14. t.Fatal("the port has not been overridden with the one passed in configuration")
  15. }
  16. }

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:

确定