Мокинг обработчика async Vertx.io

когда я выполнял синхронизацию, я писал модульные тесты, имитирующие часть персистентности, и проверял поведение вызывающего. Вот пример того, что я обычно делал:

@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.0, junit 4.12 и mockito 2.13.0. Спасибо.

Обновление. Я попытался последовать совету tsegimond, но не могу понять, как Answer и ArgumentCaptor Mockito могут мне помочь. Вот что я пробовал до сих пор. Использование 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, чтобы он возвращал false на succeed()?


person Francesco    schedule 21.12.2017    source источник
comment
Взгляните на fernandocejas.com/2014/04 / 08 /   -  person tsegismont    schedule 21.12.2017


Ответы (2)


Наконец, у меня было несколько раз, чтобы исследовать, и я справился. Вот мое решение.

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(VertxUnitRunner.class)
@PrepareForTest({ MongoClient.class })
public class PersistenceTest {

private MongoClient mongo;
private Vertx vertx;

@Before
public void initSingleTest(TestContext ctx) throws Exception {
  vertx = Vertx.vertx();
  mongo = Mockito.mock(MongoClient.class);
  PowerMockito.mockStatic(MongoClient.class);
  PowerMockito.when(MongoClient.createShared(Mockito.any(), Mockito.any())).thenReturn(mongo);
  vertx.deployVerticle(Persistence.class, new DeploymentOptions(), ctx.asyncAssertSuccess());
}

@SuppressWarnings("unchecked")
@Test
public void loadSomeDocs(TestContext ctx) {
  Doc expected = new Doc();
  expected.setName("report");
  expected.setPreview("loremipsum");
  Message<JsonObject> msg = Mockito.mock(Message.class);
  Mockito.when(msg.body()).thenReturn(JsonObject.mapFrom(expected));
  JsonObject result = new JsonObject().put("name", "report").put("preview", "loremipsum");
  AsyncResult<JsonObject> asyncResult = Mockito.mock(AsyncResult.class);
  Mockito.when(asyncResult.succeeded()).thenReturn(true);
  Mockito.when(asyncResult.result()).thenReturn(result);
  Mockito.doAnswer(new Answer<AsyncResult<JsonObject>>() {
    @Override
    public AsyncResult<JsonObject> answer(InvocationOnMock arg0) throws Throwable {
    ((Handler<AsyncResult<JsonObject>>) arg0.getArgument(3)).handle(asyncResult);
    return null;
    }
  }).when(mongo).findOne(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
  Async async = ctx.async();
  vertx.eventBus().send("persistence", new JsonObject(), msgh -> {
    if (msgh.failed()) {
    System.out.println(msgh.cause().getMessage());
    }
    ctx.assertTrue(msgh.succeeded());
    ctx.assertEquals(expected, Json.decodeValue(msgh.result().body().toString(), Doc.class));
    async.complete();
  });
  async.await();
  }
}

Используйте Powemockito, чтобы смоделировать MongoClient.createShared статический метод, чтобы у вас был макет, когда начинается вертикаль. Имитирующий обработчик async - это небольшой фрагмент кода, который нужно написать. Как видите, издевательство начинается с Message<JsonObject> msg = Mockito.mock(Message.class); и заканчивается Mockito.doAnswer(new Answer.... В методе Answer выберите параметр обработчика и заставьте его обрабатывать ваш асинхронный результат, тогда все готово.

person Francesco    schedule 26.02.2018

Обычно я использую комментарий, чтобы опубликовать это, но форматирование теряется. Принятое решение отлично работает, просто обратите внимание, что его можно немного упростить с помощью 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);
person Domenic D.    schedule 07.04.2020