I have a class which contains a private ExecutorService instance. Within the class I have a method which runs the submit method and catches the RejectedExecutionException. However I am having trouble in mocking the ExecutorService instance to throw the exception so that I can complete my test coverage. I am using JMockit 1.45.
I have already gone through the JMockit tutorial and other sites; whether i use @Mocked, @Capturing, or even create a new fake class it doesn't seem to work.
// Implemented Class:
public class TaskRegister {
private ExecutorService executor;
public TaskRegister() {
this.executor = Executors.newFixedThreadPool(5);
}
public void executeTask(Runnable task) {
try {
this.executor.submit(task);
} catch (RejectedExecutionException e) {
System.out.println(e.getMessage);
}
}
}
// Unit Test Class:
public class TestTaskRegister {
@Tested
private TaskRegister tested;
private static int counter;
@Test // this works
public void runNormalTask() throws InterruptedException {
counter = 0;
Runnable mockTask = new Runnable() {
counter++;
}
tested.executeTask(mockTask);
Thread.sleep(100); // Allow executor to finish other thread.
assertEquals(1, counter);
}
@Test // this doesn't work, will have missing invocation error.
public void throwsError (@Capturing ExecutorService executor) throws InterruptedException {
counter = 0;
// somehow the tested class still runs the actual executor
// and not the mocked one.
new Expectations() {{
executor.submit((Runnable) any);
result = new RejectedExecutionException();
}};
Runnable mockTask = new Runnable() {
// some task
}
tested.executeTask(mockTask);
Thread.sleep(100);
assertEquals(0, counter);
}
}
I expect the @Capturing to intercept the real executor implementation and throw the exception upon executor.submit being called, but it isn't doing that.
Mocking by @Capturing
is potentially expensive and can cause unexpected results in certain cases, so (currently) all java.*
classes are excluded. So, java.util.concurrent.ThreadPoolExecutor
doesn't get mocked in this test (it can be with @Mocked
).
In practice, the RejectedExecutionException
exception will never occur (not with a ThreadPoolExecutor
at least - probably only with a ForkJoinPool
). So, this test is not worth the effort. In fact, since that exception is a RuntimeException
you can simply remove the catch
block entirely.
This is one of the bad things that happen with the (ab)use of mocking libraries: people sometimes use them to test impossible situations, and therefore write useless tests.