go 测试:在延迟函数中使用t.FailNow()掩盖测试恐慌

ssgvzors  于 4个月前  发布在  Go
关注(0)|答案(8)|浏览(56)

当一个测试恐慌时,任何延迟执行的函数仍然会处理,允许测试正确清理。如果延迟执行的函数执行了 t.FailNow() ,测试输出将不包括关于恐慌或恐慌的 goroutine 跟踪的信息。
下面是一个示例:https://play.golang.org/p/gWPDVluKaST
尽管测试明显在延迟执行的函数中恐慌(使用 t.FailNow() ),但测试输出仅显示:

--- FAIL: TestPanic (0.00s)
FAIL

期望的行为应该是类似于这个示例:https://play.golang.org/p/qrLtmYnkqAh (其中延迟执行的函数调用 runtime.Goexit() )这会产生以下输出:

--- FAIL: TestPanic (0.00s)
panic: Test Panic
	panic: test executed panic(nil) or runtime.Goexit

goroutine 5 [running]:
testing.tRunner.func1(0x4560b0, 0xf)
	/usr/local/go/src/testing/testing.go:792 +0x460
runtime.Goexit()
	/usr/local/go/src/runtime/panic.go:397 +0x140
main.TestPanic.func1()
	/tmp/sandbox284554843/main.go:18 +0x20
panic(0x121940, 0x165a58)
	/usr/local/go/src/runtime/panic.go:513 +0x240
main.TestPanic(0x4560b0, 0xbab699fc)
	/tmp/sandbox284554843/main.go:20 +0x60
testing.tRunner(0x4560b0, 0x1558f8)
	/usr/local/go/src/testing/testing.go:827 +0x140
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:878 +0x3c0

我认为这是这一行的结果:
go/src/testing/testing.go
第813行 in bbae8d5
| | if!t.finished&&err==nil { |
!t.finished 将返回 false,因为 t.Now() 标记了测试已完成,而 err 将为 nil,因为 runtime.Goexit()t.FatalNow() 中正在恢复的是原始恐慌(而不是实际发生的恐慌)。
这防止了这一行上的预期恐慌:
go/src/testing/testing.go
第827行 in bbae8d5
| | panic(err) |

ars1skjm

ars1skjm1#

可能FailNow应该检查是否发生恐慌,但是为了区分panicruntime.GoExit,我们必须尝试恢复它(#25448(评论)),这会破坏与原始panic关联的堆栈信息。(我认为我在GopherCon上与@aclements讨论过这个警告...)

bpsygsoo

bpsygsoo3#

我不明白testing.FailNow如何检测到恐慌。调用recover是不起作用的,因为recover只有在直接从延迟函数中调用时才返回非nil值,而如果它是被testing.FailNow调用的话,就不会是这样的情况。
然而,这又是怎么出现的呢?为什么要推迟对FailNowFatal的调用?

qlzsbp2j

qlzsbp2j4#

嗯,好的观点。FailNow本身无法检查恐慌,但测试运行器可以。
不幸的是,似乎runtime.Goexit目前会取消panic(https://play.golang.org/p/xO5kMrMQkVS)。我不确定这是否是一个错误或Goexit的预期行为。

guykilcj

guykilcj5#

这个怎么会出现呢?为什么要推迟调用FailNow或Fatal?
被推迟的测试助手。例如,用于清理临时文件。

mbzjlibv

mbzjlibv6#

我可以将延迟函数中的调用更改为t.Fatal,然后返回,但我认为这应该可以使测试本身和延迟函数中的错误处理代码保持相同的结构。

oo7oh9g9

oo7oh9g97#

@seankhliao: t.Cleanup 问题 #51395 是否肯定是这个问题的重复?
我想知道 t.Cleanup 函数 introduced in 2020 是否可能是一个不同的路径,即使这个延迟函数的问题仍然存在。

bq3bfh9z

bq3bfh9z8#

Cleanupdefer 的简写,并且只能实现为 defer。我不认为在不解决这个问题的情况下,你能修复 Cleanup

相关问题