Repository navigation
testing: t.FailNow() in a deferred function masks test panic #29207
Description
Activity
- changed the title
[-]testing.T.FailNow() masks test panic[/-][+]testing: (*T).FailNow() in a deferred function masks test panic[/+]on Dec 13, 2018 - addedNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
on Dec 13, 2018 Probably
FailNowshould check for a panic, but in order to distinguish apanicfrom aruntime.GoExitwe must attempt torecoverit (#25448 (comment)), and that destroys the stack information associated with the originalpanic. (I think I discussed that caveat with @aclements at GopherCon...)CC @mpvl @josharian
- changed the title
[-]testing: (*T).FailNow() in a deferred function masks test panic[/-][+]testing: t.FailNow() in a deferred function masks test panic[/+]on Dec 13, 2018 I don't see how
testing.FailNowcould test for a panic. Callingrecoverwon't work, asrecoveronly returns non-nil if called directly from a deferred function, which would not be the case if it is called bytesting.FailNow.What does this come up, though? Why defer a call to
FailNoworFatal?Hmm, good point.
FailNowitself can't check for a panic, but the test runner can.Unfortunately, it appears that
runtime.Goexitcurrently cancels apanic(https://play.golang.org/p/xO5kMrMQkVS). I'm not sure whether that is a bug or the intended behavior ofGoexit.What does this come up, though? Why defer a call to FailNow or Fatal?
Test helpers that are deferred. E.g. to cleanup temp files.
I could change calls to
t.Fatalin deferred functions to bet.Errorand then return, but imo this should just work to make error handling code in the test itself and deferred functions to maintain the same structure.Cleanupis shorthand for, and can only be implemented asdefer. I don't see how you could fixCleanupwithout fixing this.- added 3 commits that reference this issue
on Nov 24, 2025 - marked testing:
T.FailNow()in cleanup function causes test report to not be printed #76447 as a duplicate of this issueon Dec 6, 2025
When a test panics, any deferred functions will still process allowing the test to properly clean up. If a deferred function executes
t.FailNow()the test output will not include any information on the panic or the panic's goroutine trace.An example is shown here: https://play.golang.org/p/gWPDVluKaST
Despite that test clearly panicking with a
t.FailNow()in the deferred function the test output only shows:The desired behavior would be along the lines of this example: https://play.golang.org/p/qrLtmYnkqAh. (Where the deferred function calls
runtime.Goexit()instead) This produces the following output:I believe this is the result of this line:
go/src/testing/testing.go
Line 813 in bbae8d5
!t.finishedwill return false becauset.Now()marks the test finished and err will be nil because theruntime.Goexit()int.FatalNow()is what is being recovered (not the original panic).This prevents the expected panic on this line:
go/src/testing/testing.go
Line 827 in bbae8d5