When a test used to hang, I'd sprinkle fmt.Println around and run it again. These days I do something else. I set a short timeout, and when it runs out the testing package panics and prints the stacks of every goroutine.
package hang
import "testing"
func TestHandoff(t *testing.T) {
results := make(chan int)
go func() {
results <- 42 // nobody reads this
}()
done := make(chan struct{})
<-done
}
go test -timeout 3s gives panic: test timed out after 3s, a list of the running tests, and then the goroutines one by one. Each has its wait reason in square brackets and the line it's sitting on. Here the two that matter are easy to spot. One is in [chan receive] on the line with <-done, the other in [chan send] on results <- 42, with a created by line under it saying who started it. It also prints how long each goroutine has been waiting, so an old leak is easy to tell from a fresh one.
Not sure why I put up with prints for so long. Probably because the default timeout is ten minutes and nobody ever waited long enough to see the dump.