erronius
erronius

Reputation: 49

Java8 UnitTesting CompletableFuture Exception

I'm using CompletableFuture Java8 class to make network calls asynchronously in Java, specifically using the supplyAsync() method. It's working great. I've figured out that I can unit test the "happy path" scenarios using CompletableFuture.completedFuture(). What I'm trying to figure out is how to unit test (if possible) the cases where an exception (i.e. CompletionException, InterruptedException, or ExecutionException) is thrown during the async task.

https://www.baeldung.com/java-completablefuture was a starting point and useful source but doesn't address this question.

My first approach does not compile:

final CompletableFuture<ResponseType> completableFutureException = CompletableFuture.completedFuture(new InterruptedException());

My second approach predictably generates a ClassCastException at runtime: final CompletableFuture completableFutureException = CompletableFuture.completedFuture(new InterruptedException());

java.lang.ClassCastException: java.lang.InterruptedException cannot be cast to ResponseType

It also sounds like the CompletableFuture<U> newIncompleteFuture() method in Java9 might help - alas, we are stuck on Java8 for the moment. If Java9 would help me here, I'd still appreciate knowing.

As I've said, I'd like to figure out if there is a reasonable way to test this in Java8 (preferably without using PowerMock, as we've had trouble getting that to play nicely with Gradle). If this really just isn't unit-testable, I can accept that and move on.

Upvotes: 0

Views: 4919

Answers (1)

MikeFHay
MikeFHay

Reputation: 9043

Java 9 introduced a new method failedFuture to meet this need. You can easily create your own equivalent method if you're running Java 8.

public static <T> CompletableFuture<T> failedFuture(Throwable ex) {
    // copied from Java 9 https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/CompletableFuture.html#failedFuture(java.lang.Throwable)
    CompletableFuture<T> f = new CompletableFuture<>();
    f.completeExceptionally(ex);
    return f;
}

CompletableFuture<ResponseType> failure = failedFuture(new InterruptedException());

Alternatively you can use supplyAsync:

CompletableFuture<ResponseType> failure = CompletableFuture.supplyAsync(() -> {throw new InterruptedException();})

Upvotes: 1

Related Questions