How can I test exception in completable future?

Let's assume your API throws if called with 0:

public static CompletableFuture<Integer> apiCall(int id) {
  return CompletableFuture.supplyAsync(() -> {
    if (id == 0) throw new RuntimeException("Please not 0!!");
    else return id;
  });
}

You can test that it works as expected with the following code (I'm using TestNG but I suspect it won't be too difficult to translate into a JUnit test):

@Test public void test_ok() throws Exception {
  CompletableFuture<Integer> result = apiCall(1);
  assertEquals(result.get(), (Integer) 1);
}

@Test(expectedExceptions = ExecutionException.class,
      expectedExceptionsMessageRegExp = ".*RuntimeException.*Please not 0!!")
public void test_ex() throws Throwable {
  CompletableFuture<Integer> result = apiCall(0);
  result.get();
}

Note that the second test uses the fact that the ExecutionException message will contain the original exception type and message and captures the expectation with a regex. If you can't do that with JUnit, you can call result.get() in a try/catch block and call throw e.getCause(); in the catch block. In other words, something like this:

@Test(expectedExceptions = RuntimeException.class,
      expectedExceptionsMessageRegExp = "Please not 0!!")
public void test_ex() throws Throwable {
  CompletableFuture<Integer> result = apiCall(0);
  try {
    result.get();
  } catch (ExecutionException e) {
    throw e.getCause();
  }
}

You can try also alternative option:

import org.hamcrest.core.IsInstanceOf;
import org.junit.rules.ExpectedException;

public class Test() {

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Test
    public void myApiCallTest() {
        thrown.expect(ExcutionException.class);
        thrown.expectCause(IsInstanceOf.instanceOf(MyException.class));
        thrown.expectMessage("the message you expected");
        myApiCall.get("");
    }
}

Assuming that:

public class myApiCall  { 
    public completableFuture get(final String id) {
        // ...
        throw new ExcutionException(new MyException("the message you expected"))
    }
}

Assume that you have a class and you want to test a method which returns a completable future:

  public class A {
    private final Api api;

    public A(Api api) { this.api = api;}

    public CompletableFuture<Void> execute(Integer input) {
       final CompletableFuture<Void> future = api.execute(input)
                .thenApplyAsync(result -> doSomething())
                .exceptionally(ex -> doFailure());
       return future;
    }
 }

To test the execution of "doSomething()" then you may use mockito and do the following:

     // prepare test
     final Api api = mock(Api.class)
     final A a = new A(api);
     when(api.execute(any(Integer.class)))
          .thenReturn(CompletableFuture.completedFuture(null));

     // execute
     final CompletableFuture<Void> result = a.execute(input);

     // validate
     ...
         

To test "doFailure" do the following:

when(api.execute(any(Integer.class))).thenAnswer(answer -> {
     CompletableFuture<Void> future = new CompletableFuture<>();
     future.completeExceptionally(new RuntimeException());
     return future;
});

// execute
final CompletableFuture<Void> result = a.execute(input);

// validate
assertTrue(result.isCompletedExceptionally());