20

I've got a class HttpClient that has a function that returns CompletableFuture:

public class HttpClient {

  public static CompletableFuture<int> getSize() {
      CompletableFuture<int> future = ClientHelper.getResults()
                 .thenApply((searchResults) -> {
                    return searchResults.size();
                });

      return future;
   }
}

Then another function calls this function:

public class Caller {

   public static void caller() throws Exception {
       // some other code than can throw an exception
       HttpClient.getSize()
       .thenApply((count) -> {
          System.out.println(count);
          return count;
       })
       .exceptionally(ex -> {
          System.out.println("Whoops! Something happened....");
       });
   }
}

Now, I want to write a test to simulates that ClientHelper.getResults fails, so for that I wrote this:

@Test
public void myTest() {
    HttpClient mockClient = mock(HttpClient.class);

    try {
        Mockito.doThrow(new CompletionException(new Exception("HTTP call failed")))
                .when(mockClient)
                .getSize();

        Caller.caller();

    } catch (Exception e) {
        Assert.fail("Caller should not have thrown an exception!");
    }
}

This test fails. The code within exceptionally never gets executed. However, if I run the source code normally and the HTTP call does fail, it goes to the exceptionally block just fine.

How must I write the test so that the exceptionally code is executed?

Maria Ines Parnisari
  • 16,584
  • 9
  • 85
  • 130

1 Answers1

27

I got this to work by doing this in the test:

CompletableFuture<Long> future = new CompletableFuture<>();
future.completeExceptionally(new Exception("HTTP call failed!"));

Mockito.when(mockClient.getSize())
        .thenReturn(future);

Not sure if this is the best way though.

Maria Ines Parnisari
  • 16,584
  • 9
  • 85
  • 130
  • 2
    I think this is the best way: CompletableFuture is a widely-used and well-tested library, so you can rely on it for testing your code instead of trying to replicate its behavior using Mockito. (Of course, Mockito is a decent way to supply the Future in your system-under-test's dependency that you mock.) – Jeff Bowman Aug 14 '17 at 21:10