简体   繁体   中英

Catch Java exception from Runnable in Unit test

I have the below code

public final class JoinableTaskPool<T> extends ABC {
       private int taskCounter;
       private final Object monitor;
       private final ExtendedThreadPoolExecutor service;
       private final CompletionService<T> compService;

       public Future<T> submit(final Callable<T> task) {
           final Future<T> result = compService.submit(task);
           service.submit(new Runnable() {
             public void run() {
                try {
                    final Future<T> result = compService.take();
                    try {
                        handler.processResult(result);
                    } catch (final Throwable t) {
                        throw new SearchException("Task has an error", t);
                    }
                } catch (InterruptedException e) {
                    throw new SearchException("Task has an error", e);
                }
            }
          } 
          return result;
       }

  public void join() {
    synchronized (monitor) {
        while (taskCounter != 0) {
            try {
                monitor.wait();
            } catch (InterruptedException e) {
                error(e, "Interrupted in join");
            }
        }
  }
  }

The ExtendedThreadPoolExecutor class is defined as follows

public class ExtendedThreadPoolExecutor extends ThreadPoolExecutor {

    public ExtendedThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if(t != null) {
            throw new SearchException("Error while executing the task", t);
        }
    }
}

I am trying to write a unit test for this method. Below is the method

@RunWith(MockitoJUnitRunner.class)
public class TestJoinableTaskPool<T> {

    private JoinableTaskPool<T> pool;

    @Before
    public void setUp() {
        pool = new JoinableTaskPool<T>(1);
    }

    @After
    public void tearDown() {
        pool.shutdown();
    }

    @Test (expected = SearchException.class)
    public void testSubmit() throws Exception{
        Callable task = (Callable<T>) () -> null;

        Mockito.when(pool.getFinishHandler().processResult(result))
                .thenThrow(RuntimeException.class);

        pool.submit(task);
    }
}

Since the SearchException exception is thrown in runnable, there is no way to access it outside the submit method. If I would have returned the Future returned by executorService.submit , I could have done a future.get() to get an exception, but I am returning another future ( result variable). So while writing the unit test I am not able to get the exception thrown.

Also I have overriden the afterExecute() in an effort to catch exception from unit test,but couldnt find a way to call it.

How do I test this exception thrown from the runnable from a unit test. Any help would be appreciated.

Putting aside that his code smells a mile away, what you can do is to create additional interface eg

public interface MyErrorHandler { handleError(Exception e)

implement it in your executor pools and call it on exception. Then you can use use Mockito.spy to see if tha method have been called or not on MyErrorHandler (cglib should allow you to do that even withount additional intrerface.)

alternatively you can define that MyExceptionHandler instance should be passed to an executor (via constructor or setter) so you will be able to provide use case dependent implementation of such callback

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM