英文:
Go hangs when running tests
问题
我正在用Go编写一个Web应用程序,它运行得很好。然而,当运行一个包的测试时,go test
命令会一直挂起(什么都不做,甚至不终止)。
我有一个用于测试的函数,它启动了服务器:
func mkroutes(t *testing.T, f func()) {
handlerRegistry = handlerList([]handler{})
middlewareRegistry = []middleware{}
if testListener == nil {
_testListener, err := net.Listen("tcp", ":8081")
testListener = _testListener
if err != nil {
fmt.Printf("[Fail] 无法启动tcp服务器:\n%s\n", err)
}
}
f()
go func() {
if err := serve(testListener, nil); err != nil {
fmt.Printf("[Fail] 服务器启动失败:\n%s\n", err)
t.FailNow()
}
}()
}
如果我更改它监听的端口,一切都运行正常(尽管所有的测试都失败了,因为它们无法连接到服务器)。这表明代码确实在运行,但是如果我在函数中记录一些东西,甚至在init
函数中记录,当端口正确时,它又会出错。
在我手动强制终止go test
命令之后,它会打印出我记录的内容,然后退出。这让我相信在执行到日志之前,还有其他东西在主线程上阻塞,但是这是不可能的,因为改变端口会有所不同。
该包没有任何init
函数,唯一在启动时运行的代码是var sessionStore = sessions.NewCookieStore([]byte("test-key"))
,它使用了github.com/gorilla/sessions
包。当我正常运行程序时,这不会引起任何问题,我在该包的源代码中也没有看到任何可能导致它在测试中表现不同的原因。
这是唯一一个导入的标准库之外的包。
我可以提供包中的任何其他代码,但是我不知道哪些是相关的。
英文:
I'm writing a web application in go and it runs just fine. However, when running the tests for a package, the go test
command just hangs (it does nothing, not even terminate).
I have a function for testing which starts the server:
func mkroutes(t *testing.T, f func()) {
handlerRegistry = handlerList([]handler{})
middlewareRegistry = []middleware{}
if testListener == nil {
_testListener, err := net.Listen("tcp", ":8081")
testListener = _testListener
if err != nil {
fmt.Printf("[Fail] could not start tcp server:\n%s\n", err)
}
}
f()
go func() {
if err := serve(testListener, nil); err != nil {
fmt.Printf("[Fail] the server failed to start:\n%s\n", err)
t.FailNow()
}
}()
}
If I change the port that it listens on, everything runs fine (all the tests fail though, since they can't connect to the server). This shows that the code is indeed running, but if I log something in the function, or even in the init
function, while the port is correct, it again breaks.
After I force the go test
command to terminate manually, it does print whatever I logged, then exit. This leads me to believe that something else is blocking on the main thread before execution reaches the log, but that's impossible since changing the port makes a difference.
The package doesn't have any init
functions and the only code that runs on startup is var sessionStore = sessions.NewCookieStore([]byte("test-key"))
which is using the package github.com/gorilla/sessions
. When I run the program normally, this causes no problems, and I don't see anything in the package's source that would cause it to behave differently in testing.
That's the only package outside the standard library which is imported.
I can provide any other code in the package, but I have no idea what's relevant.
答案1
得分: 2
首先,请注意go test
会创建、编译和运行一个测试程序,该程序会拦截每个测试的输出,因此在测试完成之前(在此时输出被打印出来之前),您将看不到测试的输出。
您的代码存在两个问题:
-
如果无法启动TCP服务器t,则只会在此处执行Printf并继续,仿佛一切正常。
-
您从与测试运行不同的goroutine中调用了t.FailNow。您不能这样做。请参阅http://golang.org/pkg/testing/#T.FailNow
修复这些问题可能至少能显示出其他出错的地方。另外:请查看net/http包是如何进行测试的。
英文:
First: Note that go test
will create, compile and run a test program which intercept output from each test so you will not see output from your tests until the test finishes (in this moment the output is printed).
Two issues with your code:
-
If you cannot start the tcp server t is not notified, you only do Printf here and continue as if everything was fine.
-
You call t.FailNow from a different goroutine than your test runs in. You must not do this. See http://golang.org/pkg/testing/#T.FailNow
Fixing those might at least show what else goes wrong. Also: Take a look at how package net/http does it's testing.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论