How to properly mock a private ExecutorService's submit method in JMockit

Fu Jie :

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.

Rogério :

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.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=153544&siteId=1