testify
testify copied to clipboard
Customize require behavior to allow it to panic
I'm using require extensively as I want the test to fail immediately (makes writing tests much easier).
However, the test suite would time out when I started a consumer in a goroutine, which would read a chan and check the content it receives, and produced values in my the goroutine running the test.
Turns out this quirk is documented in T.FailNow():
FailNow must be called from the goroutine running the test or benchmark function, not from other goroutines created during the test. Calling FailNow does not stop those other goroutines.
I'm going to invert the producer/consumer goroutine to work around this, but I was wondering if there was any way for testify to provide a way to do it by default ?
@Geod24 Could you provide a minimal example reproducing this behavior?
package testme
import (
"fmt"
"testing"
"github.com/stretchr/testify/require"
)
func TestPanic(t *testing.T) {
channel := make(chan int)
signal := make(chan struct{})
// Start consumer
go func () {
for i := 0; i < 4; i++ {
recv := <-channel
fmt.Println("Received: ", recv, ", expecting: ", i)
require.Equal(t, recv, i)
}
signal<-struct{}{}
}()
channel <- 0
channel <- 1
channel <- 2
channel <- 42
<-signal
}
% go test ./... -timeout=30s
Received: 0 , expecting: 0
Received: 1 , expecting: 1
Received: 2 , expecting: 2
Received: 42 , expecting: 3
panic: test timed out after 30s
goroutine 23 [running]:
testing.(*M).startAlarm.func1()
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1296 +0xfd
created by time.goFunc
/usr/local/Cellar/go/1.11/libexec/src/time/sleep.go:172 +0x44
goroutine 1 [chan receive]:
testing.(*T).Run(0xc000116100, 0x12e981b, 0x9, 0x12fbfc0, 0x1076286)
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:879 +0x37a
testing.runTests.func1(0xc000116000)
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1119 +0x78
testing.tRunner(0xc000116000, 0xc0000b9e08)
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:827 +0xbf
testing.runTests(0xc0000a8400, 0x14faed0, 0x1, 0x1, 0x100d40f)
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1117 +0x2aa
testing.(*M).Run(0xc000112000, 0x0)
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:1034 +0x165
main.main()
_testmain.go:42 +0x13d
goroutine 21 [chan receive]:
_/Users/geod24/projects/testme.TestPanic(0xc000116100)
/Users/geod24/projects/testme/testify_test.go:29 +0x117
testing.tRunner(0xc000116100, 0x12fbfc0)
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
/usr/local/Cellar/go/1.11/libexec/src/testing/testing.go:878 +0x353
FAIL _/Users/geod24/projects/testme 30.022s
As you can see, the test times out instead of hard failing when require fails
I ran into this problem when using github.com/vektra/mockery in asynchronous code. The mocks are called within a goroutine, and since they use Mock.Called (which eventually calls FailNow on failures), the tests hang instead of reporting failures.
A workaround to get the mocks to immediately panic instead is call .Test(nil) on your Mock. When test failures happen, the goroutine will panic (causing the entire test to panic with the failure message).
testify can't magically workaround limitations of the testing package it relies on.
testify will have that limitation as long as testing has it.
testify has so many bugs due to the poor quality of some external contributions that we (the maintainers) could not absorb the load of enabling parallel testing beyond testing.T.Parallel. We do not have the resources of the Go team to ensure reviews.