Mocking time and testing event loops in Go
dmitryfrank.com
Mocking time and testing event loops in Go
1–10 of 35 posts
Re: Mocking time and testing event loops in Go
#2Re: Mocking time and testing event loops in Go
#3- Even though Clock is an interface, Timer is not. This means that if you want to use that package in combination with gomock, you're out of luck.
- The Clock interface doesn't provide a wrapper for context.WithTimeout(), which also depends on the system clock.
- Nit: The Clock interface also exposes functions like time.After(), which should in my opinion never be used in production code, as they don't support efficient cancelation. You should use timers instead.
In the end I resorted to writing my own set of interfaces.
Code: https://github.com/buildbarn/bb-storage/tree/master/pkg/cloc...
Documentation: https://pkg.go.dev/github.com/buildbarn/bb-storage/pkg/clock
Re: Mocking time and testing event loops in Go
#4I am using java.time.Clock class in Java - really similar to what’s mentioned for Go in the article! It works great and enables us to write reliable, comprehensive, reproduce-able unit tests.
Re: Mocking time and testing event loops in Go
#5Typically you would just do this with contexts. I was going to write down some examples of not using contexts, but I think your best bet is to just rewrite code to take contexts when it can be cancelled. A common mistake that people make is timing out some operation, usually happening in another goroutine, and then their program ends up leaking goroutines and crashing because the abandoned work was never correctly cleaned up. If your API doesn't allow you to abort, you will have to modify it, because downstream RPC servers come and go, people press the "stop" button in their browser, TCP connections close, etc.
Re: Mocking time and testing event loops in Go
#6I am using java.time.Clock class in Java - really similar to what’s mentioned for Go in the article! It works great and enables us to write reliable, comprehensive, reproduce-able unit tests.
Re: Mocking time and testing event loops in Go
#7I also started using benbjohnson/clock about a year ago, but discovered that it wasn't a perfect fit: - Even though Clock is an interface, Timer is not. This means that if you want to use that package in combination with gomock, you're out of luck. - The Clock interface doesn't provide a wrapper for context.WithTimeout(), which also depends on the system clock. - Nit: The Clock interface also exposes functions like t…
Re: Mocking time and testing event loops in Go
#8 defer dates.SetNowSource(dates.DefaultNowSource)
dates.SetNowSource(dates.NewSequentialNowSource(time.Date(2018, 10, 18, 14, 20, 30, 123456, time.UTC)))
dates.Now()Re: Mocking time and testing event loops in Go
#9Re: Mocking time and testing event loops in Go
#10Or, create the timer outside and inject its channel. Want to fire the timer? Just write to the channel.
If you do expect to get a lot of value from testing the event loop, blocking on individual messages received or not received as in the article is a reasonable way to de-flakify your tests (in that case, I'd expect the tests to inject mocks and/or use private interfaces). However, it is a code smell if any other tests are depending on the details of that event loop.