You want to call a panic in a piece of code and have the test not fail?
In a deferred function, call recover()
. If it has a return value that is not nil, it succeeded and caught the panic
i.e. if err == nil
then you can call t.Fatal()
in your test.
Here's the setup code
Let's start a new package to demonstrate this:
mkdir panicker && cd panicker && go mod init panicker && touch panicker_test.go
Here's the content of panicker_test.go:
package panicker
import "testing"
func Panics() {
panic("I panic!")
}
func TestPanics(t *testing.T) {
Panics()
}
Here's how she runs:
; go test -v panicker
=== RUN TestPanics
--- FAIL: TestPanics (0.00s)
panic: I panic! [recovered]
panic: I panic!
goroutine 34 [running]:
testing.tRunner.func1.2({0x10441d540, 0x1044455e0})
/opt/homebrew/Cellar/go/1.22.2/libexec/src/testing/testing.go:1631 +0x1c4
testing.tRunner.func1()
/opt/homebrew/Cellar/go/1.22.2/libexec/src/testing/testing.go:1634 +0x33c
panic({0x10441d540?, 0x1044455e0?})
/opt/homebrew/Cellar/go/1.22.2/libexec/src/runtime/panic.go:770 +0x124
panicker.Panics(...)
/Users/gwyn/Source/panicker/panicker_test.go:6
panicker.TestPanics(0x14000124680?)
/Users/gwyn/Source/panicker/panicker_test.go:17 +0x30
testing.tRunner(0x14000124680, 0x104444dc0)
/opt/homebrew/Cellar/go/1.22.2/libexec/src/testing/testing.go:1689 +0xec
created by testing.(*T).Run in goroutine 1
/opt/homebrew/Cellar/go/1.22.2/libexec/src/testing/testing.go:1742 +0x318
FAIL panicker 0.082s
FAIL
Here's the implementation
Update TestPanics to contain a deferred call to recover().
package panicker
import "testing"
func Panics() {
panic("I panic!")
}
func TestPanics(t *testing.T) {
defer func() {
err := recover()
if err == nil {
t.Fatalf("Expected panic with invalid address, received %v", err)
}
}()
Panics()
}
How does she run now?
; go test -v panicker
=== RUN TestPanics
--- PASS: TestPanics (0.00s)
PASS
ok panicker 0.123s
Notice the error check condition: recover() is non-nil if it's actually called; if recover()'s return value is nil, it was never triggered, so we didn't actually trigger our expected error.