This is an interesting problem that's not currently solved.
It was originally developed as part of Canonical's Juju project.
To wait for goroutines to finish, you can use the
WaitAdvance method, which waits for at least n goroutines to block
on the clock before advancing time. This relies, of course, on all the code under test using the Clock interface,
but that's not usually that hard to arrange.
There are a couple of deeper problems with this particular approach though:
- in order to use WaitAdvance, you need to know the total number of goroutines involved, but this is implementation-dependent, so someone
can break tests by making an apparently innocuous change that happens to change goroutine count.
- it's still easy to make mistakes. It's easy to assume that when the goroutines are blocked, the state that you're trying to observe
is static, but there may well be other goroutines still running that have previously been triggered. This means that one
can end up polling state anyway if you're trying to test behaviour of an independent "agent" goroutine.
In the end, I've largely given up on this fake clock approach in favour of testing with real time (on the order of 10s of milliseconds not seconds)
and polling to wait for externally visible changes. This approach isn't ideal either - if you make the time intervals too short, your
tests will be flaky; too long and you're waiting too long for tests to run. But at least the tests aren't relying on details of
the internal implementation.
I'd love to see a way of fixing this in the standard Go runtime, but it's not easy. Goroutines can be blocked in system calls (e.g. making an HTTP call),
while still making progress, so just "wait for everything to be blocked before advancing the clock" isn't a sufficient heuristic.
Also I'm not sure that a single clock is good enough because you might well want to be able to time out your tests even as you're faking out
the clock for the code being tested.
cheers,
rog.