3 ms·
In my experience so far, everything beyond mocking the current time is out on the long tail of tests that are expensive to write and provide little value. When
by physicles 6y ago
In my experience so far, everything beyond mocking the current time is out on the long tail of tests that are expensive to write and provide little value. When I've run into a class with a time-based event loop, I isolate the timing code as well as is reasonable and just test everything else.
Or, 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.
- cle 6y agoIt can be useful to directly unit test edge cases in critical concurrent code, because they are otherwise difficult to test deterministically. But like you said, I've also found them difficult to write and maintain (re-reading some of them months later is usually hard). The tests usually end up with 2-3x channels than the prod code, because I'm forced to inject channels into various places to control the synchronization. Sometimes though, in a critical code path, it's worth it.
- jeffbee 6y agoIsn't this basic design for testability (TDD, if you like)? If you need some synchronization facilities to make your unit tests end cleanly, then you also need those facilities in your general APIs because applications _also_ have boundary conditions, and pretending that your application exists on an infinite timeline that neither starts nor ends is naive.
- cle 6y agoIt's not about ending cleanly, it's about behaving correctly. I would say that there's nothing "basic" about testing concurrent code--it's always been hard, no matter what language you use. Exposing your concurrency guts in the API doesn't make the intrinsic complexity go away, it just shifts it somewhere else.