smartystreets / goconvey

Go testing in the browser. Integrates with `go test`. Write behavioral tests in Go.
http://smartystreets.github.io/goconvey/
Other
8.23k stars 555 forks source link

Code that calls panic is NOT reported as such #98

Closed mdwhatcott closed 10 years ago

mdwhatcott commented 10 years ago

@swaits submitted an example that called panic yet GoConvey calmly reported no errors. As expected, execution stopped after the panic because none of the assertions that followed the panic were executed or reported. Very strange.

mdwhatcott commented 10 years ago

@swaits - Ok, this is a really "fun" one. It turns out that your code was calling panic(nil). Stated in a different way, the error your code was passing into the panic function was nil. So, when GoConvey calls recover() to maintain control of execution it appeared that there was no panic because what the recover function returned was nil! So, the moral of the story here is don't ever call panic with nil. It prevents the recovering method from knowing anything interesting about what has happened. I promise I'm not making this up :)

The only way I was able to discover this was by commenting out the panics in the Read method and return dummy values. Then the tests started failing (which is better than passing for no good reason) and I knew I was on to something.

I wish there was something more I could do here to help but unfortunately, there simply is no way to know that panic was called if the "error" it receives is nil. I've added this to the wiki as a warning to future users of GoConvey and Go in general. At least we can say we've learned something interesting about Go. Thanks for providing the learning opportunity.

mdwhatcott commented 6 years ago

https://github.com/golang/go/issues/25448

mdwhatcott commented 8 months ago

Well, 10 years later with the release of Go 1.21, we finally have closure!

Go 1.21 now defines that if a goroutine is panicking and recover was called directly by a deferred function, the return value of recover is guaranteed not to be nil. To ensure this, calling panic with a nil interface value (or an untyped nil) causes a run-time panic of type *runtime.PanicNilError.

https://go.dev/doc/go1.21

swaits commented 7 months ago

Wow, nice @mdwhatcott!