模拟Vertx.io异步处理程序

时间:2017-12-21 11:34:39

标签: java unit-testing mockito vert.x asynccallback

当我同步时,我编写了单元测试来模拟持久性部分并检查调用者的行为。这是一个关于我通常做的事情的例子:

@Mock
private OfferPersistenceServiceImpl persistenceService;
@Inject
@InjectMocks
private OfferServiceImpl offerService;
...
@Test
public void createInvalidOffer() {
  offer = new Offer(null, null, null, null, null, 4, 200D, 90D);
  String expectedMessage = Offer.class.getName() + " is not valid: " + offer.toString();
  Mockito.when(persistenceService.create(offer)).thenThrow(new IllegalArgumentException(expectedMessage));
  Response response = offerService.create(offer);
  Mockito.verify(persistenceService, Mockito.times(1)).create(offer);
  Assert.assertEquals(INVALID_INPUT, response.getStatus());
  String actualMessage = response.getEntity().toString();
  Assert.assertEquals(expectedMessage, actualMessage);
}

但现在我爱上了Vertx.io(我很新),我想要异步。尼斯。但是Vertx有处理程序,因此要模拟的新持久性组件如下所示:

...
mongoClient.insert(COLLECTION, offer, h-> {
  ...
});

所以我猜测如何模拟处理程序h来测试使用mongoClient的类,或者即使它是使用Vertx.io进行测试的正确方法。我使用的是vertx.io 3.5.0junit 4.12mockito 2.13.0。感谢。

更新 我试图遵循tsegimond的建议,但我无法理解Mockito的AnswerArgumentCaptor如何帮助我。这是我到目前为止所尝试的。 使用ArgumentCaptor

JsonObject offer = Mockito.mock(JsonObject.class);
Mockito.when(msg.body()).thenReturn(offer);         
Mockito.doNothing().when(offerMongo).validate(offer);
RuntimeException rex = new RuntimeException("some message");
...
ArgumentCaptor<Handler<AsyncResult<String>>> handlerCaptor =
ArgumentCaptor.forClass(Handler.class);
ArgumentCaptor<AsyncResult<String>> asyncResultCaptor =
ArgumentCaptor.forClass(AsyncResult.class);
offerMongo.create(msg);
Mockito.verify(mongoClient,
Mockito.times(1)).insert(Mockito.anyString(), Mockito.any(), handlerCaptor.capture());
Mockito.verify(handlerCaptor.getValue(),
Mockito.times(1)).handle(asyncResultCaptor.capture());
Mockito.when(asyncResultCaptor.getValue().succeeded()).thenReturn(false);
Mockito.when(asyncResultCaptor.getValue().cause()).thenReturn(rex);
Assert.assertEquals(Json.encode(rex), msg.body().encode());

并使用Answer

ArgumentCaptor<AsyncResult<String>> handlerCaptor =
ArgumentCaptor.forClass(AsyncResult.class);
AsyncResult<String> result = Mockito.mock(AsyncResult.class);
Mockito.when(result.succeeded()).thenReturn(true);
Mockito.when(result.cause()).thenReturn(rex);
Mockito.doAnswer(new Answer<MongoClient>() {
  @Override
  public MongoClient answer(InvocationOnMock invocation) throws Throwable {
    ((Handler<AsyncResult<String>>)
    invocation.getArguments()[2]).handle(handlerCaptor.capture());
        return null;
      }
    }).when(mongoClient).insert(Mockito.anyString(), Mockito.any(),
Mockito.any());
userMongo.create(msg);
Assert.assertEquals(Json.encode(rex), msg.body().encode());

现在我感到困惑。有没有办法模仿AsyncResult让它在succeed()上返回false?

1 个答案:

答案 0 :(得分:1)

通常,我会使用评论来发布此内容,但是格式会丢失。公认的解决方案效果很好,只需注意,可以使用Java 8+对其进行一些简化,并且可以使用实际的对象而不是JSON。

doAnswer((Answer<AsyncResult<List<Show>>>) arguments -> {
            ((Handler<AsyncResult<List<Show>>>) arguments.getArgument(1)).handle(asyncResult);
            return null;
        }).when(showService).findShowsByShowFilter(any(), any());

getArgument(1),引用诸如以下方法的处理程序参数的索引:

@Fluent
@Nonnull
ShowService findShowsByShowFilter(@Nonnull final ShowFilter showFilter,
                                  @Nonnull final Handler<AsyncResult<List<Show>>> resultHandler);