testify icon indicating copy to clipboard operation
testify copied to clipboard

Customize require behavior to allow it to panic

Open Geod24 opened this issue 7 years ago • 3 comments

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 avatar Aug 23 '18 05:08 Geod24

@Geod24 Could you provide a minimal example reproducing this behavior?

HaraldNordgren avatar Sep 11 '18 17:09 HaraldNordgren

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

Geod24 avatar Sep 12 '18 01:09 Geod24

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).

dgunay avatar Jan 07 '23 00:01 dgunay

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.

dolmen avatar Jul 31 '23 14:07 dolmen