Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test a code snippet running inside executor service, instead waiting on Thread.sleep(time)

Tags:

How to unit test a code that is running in executor service? In my situation,

public void test() {
    Runnable R = new Runnable() {
        @Override
        public void run() {
            executeTask1();
            executeTask2();
        }
    };

    ExecutorService executorService = Executors.newSingleThreadExecutor();
    executorService.submit(R);
}

When I am unit testing, I would like to make some validations that method executes.

I am executing this in an executor service, as it makes some network operations.

In my unit testing, I had to wait until this method finishes execution. Is there a better way I can do this, instead of waiting for Thread.sleep(500).

Unit testing code snippet:

@Test
public void testingTask() {
    mTestObject.test();
    final long threadSleepTime = 10000L;
    Thread.sleep(threadSleepTime);
    verify(abc, times(2))
            .acquireClient(a, b, c);
    verify(abd, times(1)).addCallback(callback);
}

Note: I am passing an executor service object into this constructor class. I would like to know if there is a good way of testing instead of waiting for sleep time.

like image 313
samuel koduri Avatar asked Sep 24 '17 18:09

samuel koduri


People also ask

How does parent thread wait till all the threads complete in a executor service?

When using an Executor, we can shut it down by calling the shutdown() or shutdownNow() methods. Although, it won't wait until all threads stop executing. Waiting for existing threads to complete their execution can be achieved by using the awaitTermination() method.

How do I mock an executor service?

You can use the @Spy annotation. @RunWith(MockitoJUnitRunner. class) public class MadeUpClassNameTest{ @Spy private final ExecutorService executor = Executors. newFixedThreadPool(2); @Test ... }

How do I stop the ExecutorService thread?

To properly shut down an ExecutorService, we have the shutdown() and shutdownNow() APIs. The shutdown() method doesn't cause immediate destruction of the ExecutorService. It will make the ExecutorService stop accepting new tasks and shut down after all running threads finish their current work: executorService.

How do you write a Junit test case for threads?

Spawn some threads. Have the main thread wait or sleep. Perform assertions from within the worker threads (which via ConcurrentUnit, are reported back to the main thread) Resume the main thread from one of the worker threads once all assertions are complete.


2 Answers

You could also implement an ExecutorService yourself that will run the task in the same thread. For example:

public class CurrentThreadExecutor implements Executor {
    public void execute(Runnable r) {
        r.run();
    }
}

And then you could inherit from AbstractExecutorService and use this implementation.

If you're using Guava, another easy one is to use MoreExecutors.newDirectExecutorService() since that does the same thing without you having to create one yourself.

like image 87
claudio Avatar answered Sep 18 '22 11:09

claudio


Google Guava provides a great class called MoreExecutors which helped me out when testing code that runs in parallel threads via Executor or ExecutorService in JUnit. It lets you create Executor instances that just run everything in the same thread, essentially as a mock of a real Executor. The issue is when things get run in other threads that JUnit isn't aware of, so these Executors from MoreExecutors make everything much easier to test since it's not actually parallel in another thread.

See the MoreExecutors documentation https://google.github.io/guava/releases/19.0/api/docs/com/google/common/util/concurrent/MoreExecutors.html

You can modify your class constructor, or add a new constructor that you only use in tests, which lets you provide your own Executor or ExecutorService. Then pass in the one from MoreExecutors.

So in the test file you'd create the mock executor using MoreExecutors

ExecutorService mockExecutor = MoreExecutors.newDirectExecutorService();

// or if you're using Executor instead of ExecutorService you can do MoreExecutors.newDirectExecutor()

MyService myService = new MyService(mockExecutor);

Then in your class, you only create a real Executor if it wasn't provided in the constructor

public MyService() {}
    ExecutorService threadPool;

    public MyService(ExecutorService threadPool) {
        this.threadPool = threadPool;
    }

    public void someMethodToTest() {
        if (this.threadPool == null) {
            // if you didn't provide the executor via constructor in the unit test, 
            // it will create a real one
            threadPool = Executors.newFixedThreadPool(3);
        }
        threadPool.execute(...etc etc)
        threadPool.shutdown()
    }
}
like image 35
ejfrancis Avatar answered Sep 16 '22 11:09

ejfrancis