在测试中模拟 CompletionException

Posted

技术标签:

【中文标题】在测试中模拟 CompletionException【英文标题】:Simulate CompletionException in a test 【发布时间】:2018-01-21 06:12:29 【问题描述】:

我有一个类 HttpClient,它有一个返回 CompletableFuture 的函数:

public class HttpClient 

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

      return future;
   

然后另一个函数调用这个函数:

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....");
       );
   

现在,我想写一个测试来模拟ClientHelper.getResults 失败,所以我写了这个:

@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!");
    

此测试失败。 exceptionally 中的代码永远不会被执行。但是,如果我正常运行源代码并且 HTTP 调用确实失败了,它会转到 exceptionally 块就好了。

我必须如何编写测试才能执行exceptionally 代码?

【问题讨论】:

【参考方案1】:

我在测试中这样做了:

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

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

不确定这是否是最好的方法。

【讨论】:

我认为这是最好的方法:CompletableFuture 是一个广泛使用且经过良好测试的库,因此您可以依赖它来测试您的代码,而不是尝试使用 Mockito 复制其行为。 (当然,Mockito 是在您模拟的被测系统的依赖项中提供 Future 的一种不错的方式。)

以上是关于在测试中模拟 CompletionException的主要内容,如果未能解决你的问题,请参考以下文章

如何使用@WebMvcTest 春季测试在模拟服务中注入模拟的restTemplate

如何在集成测试中重置 Firestore 模拟器

使用proxyquire和mocha在单元测试中模拟方法调用时如何模拟时间延迟(超时)?

如何在单元测试中模拟缺乏网络连接

如何在集成测试中模拟 BLoC

角度测试 - 如何在角度测试中模拟 document.getElementbyId?