Testing code which uses ScheduledExecutorService (without using Sleep)

Mark Cuban picture Mark Cuban · Sep 8, 2015 · Viewed 8.1k times · Source

I have a validation object which runs input through a series of checks. If an input fails any of the checks, the validation ends.

Inputs which pass all the checks get grouped based on a sliding time window. This window kicks off when the first piece of input arrives. So this is the flow:

1) First input arrives. 2) Input passes all checks. 3) Since there is no active timer, input is put in a new basket. Timer window begins for N seconds. 4) Any subsequent input passing all checks within this timer window will get grouped into the same basket. 5) Once the timer goes off, the basket is dispatched. 6) Any further valid input will start a new timer, and the process repeats.

At the moment, to make sure valid inputs get grouped together properly, I'm using Thread.sleep in the unit tests (i.e. Once I send a number of inputs, I sleep for a few seconds, then wake up and make sure the basket which got dispatched contains everything expected).

This is starting to become annoying as I have over 700 unit tests and this test collection is the bottleneck each time I run the complete suite.

The time window is simply a ScheduledExecutorService. To be able to test this functionality more quickly, should I create a settable time window object?

Answer

Solomon Slow picture Solomon Slow · Sep 8, 2015

Your "unit tests" sound a little bit like integration tests. You are not only testing the unit that uses the ScheduledExecutorService, but you are also testing the ScheduledExecutorService itself.

A better approach would be to inject a mock ScheduledExecutorService. In other words, you shouldn't need to test that the timed event actually happens four seconds later; you should only need to test that your unit asked the scheduler to run it four seconds later.

That's where mocks come in. You inject the mock scheduler, perform some operation on your unit that should cause it to interact with the scheduler, and then you can interrogate the mock to verify that the interaction actually happened in the expected way.

If you do it right, each test case can complete in milliseconds or maybe microseconds instead of seconds.