### Question:
AsyncExecutor { public Future<?> execute(Runnable runnable) { CompletableFuture<?> result = new CompletableFuture<Object>() { @Override public boolean cancel(boolean mayInterruptIfRunning) { throw new UnsupportedOperationException("Calling thread.stop is deprecated. Arrange termination directly with the runnable"); } }; factory.newThread(() -> { try { runnable.run(); } finally { result.complete(null); } }).start(); return result; } AsyncExecutor(ThreadFactory factory); Future<?> execute(Runnable runnable);  }### Answer:
@Test public void execute_shouldCreateAndStartAThreadWithTheProvidedRunnableAndReturnAFuture() throws Exception { CountDownLatch latch = new CountDownLatch(1); Future<?> result = asyncExecutor.execute(latch::countDown); latch.await(5, TimeUnit.SECONDS); verify(factory).newThread(any()); assertEquals(0, latch.getCount()); assertNotNull(result); assertNotNull(createdThread); assertNotEquals(Thread.State.NEW, createdThread.getState()); }
@Test public void get_shouldJoinTheCreatedThread_givenAFutureReturnedByExecute() throws Exception { long startTime = System.nanoTime(); Future<?> result = asyncExecutor.execute(suppressCheckedExceptions(() -> Thread.sleep(250L))); result.get(); long endTime = System.nanoTime(); assertThat(endTime - startTime, isGreaterThan(100 * 1000000L)); }
@Test public void get_shouldSucceed_whenTheThreadThrowsAnException_givenAFutureReturnedByExecute() throws Exception { Future<?> result = asyncExecutor.execute(() -> {throw new RuntimeException("blah"); }); result.get(100, TimeUnit.MILLISECONDS); }
@Test public void getWithATimeout_shouldSucceed_whenTheThreadEndsQuickly_givenAFutureReturnedByExecute() throws Exception { Future<?> result = asyncExecutor.execute(suppressCheckedExceptions(() -> Thread.sleep(50L))); result.get(100, TimeUnit.MILLISECONDS); }
@Test public void getWithATimeout_shouldThrowATimeoutException_whenTheThreadDoesNotEndQuickly_givenAFutureReturnedByExecute() throws Exception { Future<?> result = asyncExecutor.execute(suppressCheckedExceptions(() -> Thread.sleep(250L))); try { result.get(50, TimeUnit.MILLISECONDS); fail("Expected an exception"); } catch (TimeoutException ignore) {} }
@Test public void cancel_shouldThrowAnUnsupportedOperationException_givenAFutureReturnedByExecute() throws Exception { Future<?> result = asyncExecutor.execute(() -> {}); try { result.cancel(true); fail("Expected an exception"); } catch (UnsupportedOperationException ignore) {} }
@Test public void isCancelled_shouldReturnFalse_givenAFutureReturnedByExecute() throws Exception { Future<?> result = asyncExecutor.execute(() -> {}); assertFalse(result.isCancelled()); }
@Test public void isDone_shouldReturnTrue_whenTheThreadIsAlive_givenAFutureReturnedByExecute() throws Exception { CountDownLatch latch = new CountDownLatch(1); Future<?> result = asyncExecutor.execute(suppressCheckedExceptions(latch::await)); try { assertFalse(result.isDone()); } finally { latch.countDown(); } }
@Test public void isDone_shouldReturnFalse_whenTheThreadIsFinished_givenAFutureReturnedByExecute() throws Exception { Future<?> result = asyncExecutor.execute(() -> {}); Thread.sleep(50L); assertTrue(result.isDone()); }