Writing Junit test cases for a multithreaded program can be tricky. For unit test, you need a predictable result to validate against. Let’s say that ExecutorService is running two tasks in parallel in two different threads. You want to put the results back in a list. Then how would you know which result gets stored where? First item in the list can have the second task result because execution was happening concurrently. That would make writing assert statements difficult.
But there is a more pressing concern here. If you are using actual background threads for running tasks, your Junit test will execute the main function thread & exit. It won’t wait for background threads to complete. So you would get error when assert statements execute.
To fix this, you need to have a Java ExecutorService which uses only one thread. That will execute any number of tasks sequentially one by one. But that is not sufficient. You need to make sure you are not creating a new background thread. Instead of that, ExecutorService should use current thread (the thread where Junit test is running). Then test function won’t exit before task results are populated.
Option 1:
Guava is a pretty popular Java library from Google. It has MoreExecutors.newDirectExecutorService() method which gives you a ready-made ExecutorService which runs task in same thread one by one. But it is not ideal to use with Mockito framework.
The ExecutorService returned is a final class. So Mockito framework can’t mock or spy the object. You won’t be able to define desired behaviour or verify method run unless you can spy the ExecutorService object.
Option 2:
Create a ExecutorService on your own as below:
private static ExecutorService currentThreadExecutorService() {
CallerRunsPolicy callerRunsPolicy =
new ThreadPoolExecutor.CallerRunsPolicy();
return new ThreadPoolExecutor(0, 1, 0L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), callerRunsPolicy) {
@Override
public void execute(Runnable command) {
callerRunsPolicy.rejectedExecution(command, this);
}
};
}
We did a little trick above. We defined a CallerRunsPolicy policy object and used it inside execute() method of ThreadPoolExecutor. Using that policy, we are doing rejected execution of all the tasks submitted. When rejectedExecution() method is used, task execution happens in caller’s thread.
That was our goal. This ExecutorService is not final. So Mockito framework can be used to spy it. This way you can have a predictable ExecutorService to run your Java test cases.