### Question:
ModernAsyncTask { public final ModernAsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec, Params... params) { if (mStatus != Status.PENDING) { switch (mStatus) { case RUNNING: throw new IllegalStateException("Cannot execute task:" + " the task is already running."); case FINISHED: throw new IllegalStateException("Cannot execute task:" + " the task has already been executed " + "(a task can be executed only once)"); default: throw new IllegalStateException("We should never reach this state"); } } mStatus = Status.RUNNING; onPreExecute(); mWorker.mParams = params; exec.execute(mFuture); return this; } ModernAsyncTask(); @RestrictTo(LIBRARY_GROUP) static void setDefaultExecutor(Executor exec); final Status getStatus(); final boolean isCancelled(); final boolean cancel(boolean mayInterruptIfRunning); final Result get(); final Result get(long timeout, TimeUnit unit); final ModernAsyncTask<Params, Progress, Result> execute(Params... params); final ModernAsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
            Params... params); static void execute(Runnable runnable); static final Executor THREAD_POOL_EXECUTOR; }### Answer:
@LargeTest @Test public void testException() throws Throwable { final CountDownLatch calledOnCancelled = new CountDownLatch(1); InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { @Override public void run() { mModernAsyncTask = new ModernAsyncTask() { @Override protected Object doInBackground(Object[] params) { throw new RuntimeException(); } @Override protected void onPostExecute(Object o) { fail("onPostExecute should not be called"); } @Override protected void onCancelled(Object o) { calledOnCancelled.countDown(); } }; } }); mModernAsyncTask.executeOnExecutor(new Executor() { @Override public void execute(@NonNull Runnable command) { try { command.run(); fail("Exception not thrown"); } catch (Throwable tr) { } } }); if (!calledOnCancelled.await(5, TimeUnit.SECONDS)) { fail("onCancelled not called"); } }