如何对包含vertx()。eventBus()。send()的方法进行单元测试?

时间:2018-07-11 11:36:01

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

令人沮丧。我到处看的地方,都看到了测试异步Vertx代码的示例,但是没有什么比我要测试的更接近。

  • Vertx 3.3.2,JUnit 4.12,Java 8

被测方法将一条消息发送到事件总线。我想验证eventBus()。send()响应处理程序中正在发生的事情。

如此,我看到许多示例都在TEST ITSELF中具有eventBus()。send()方法(因此,测试事件总线的另一端-使用者)我想在.send()中测试响应处理程序

我已经在测试中尝试了Async。尝试过ArgumentCaptor。尝试使用Thread.sleep()。尝试过doAnswer()。似乎没有任何东西可以测试(a)等待被测方法中的异步eventBus()。send()调用完成,以及(b)能够验证()是否存在交互(我认为这可能必须做一下Vertx.TestContext和JUnit.Runner Context之间的区别。.

代码: 被测方法:

public void sendToEventBusAddress(RoutingContext context, String requestId, String userId) {
    List<String> stuff = split(context.request().getParam("stuffToSplit"));
    JsonObject eventBusMessage = new JsonObject()
            .put("requestId", requestId)
            .put("stuffList", new JsonArray(stuff))
            .put("userId", userId);
    LOGGER.info("Putting message: {} onto the EventBus at address: {}", eventBusMessage.encodePrettily(), EventBusEndpointEnum.STUFF_ACCESS.getValue());
    context.vertx().eventBus().send(EventBusEndpointEnum.STUFF_ACCESS.getValue(), eventBusMessage, new DeliveryOptions().setSendTimeout(timeout), async -> {
        if (async.succeeded()) {
            LOGGER.info("EventBus Response: {}", async.result().body().toString());
            context.response().setStatusCode(HttpStatus.SC_OK);
            context.response().headers().set(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN);
            context.response().end(async.result().body().toString());
        } else {
            LOGGER.error(errorMessage);
            context.response().setStatusCode(HttpStatus.SC_BAD_REQUEST);
            context.response().end(errorMessage);
        }
    });
}

简化的(无效的)测试用例和类:

@RunWith(VertxUnitRunner.class)
public class MyBrokenTest {
    @Mock private RoutingContext routingContext;
    @Mock private HttpServerRequest contextRequest;
    @Mock private HttpServerResponse contextResponse;
    @Mock private MultiMap responseHeaders;

    @Rule public RunTestOnContext rule = new RunTestOnContext();

    @Before
    public void setUp(TestContext context) {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testOne(TestContext context) {
        when(routingContext.vertx()).thenReturn(rule.vertx());
        when(routingContext.request()).thenReturn(contextRequest);
        when(contextRequest.getParam("stuffToSplit")).thenReturn("04MA");
        when(routingContext.response()).thenReturn(contextResponse);
        when(contextResponse.headers()).thenReturn(responseHeaders);

        rule.vertx().eventBus().consumer(EventBusEndpointEnum.STUFF_ACCESS.getValue(), res -> {
            res.reply("yo");
        });

        ClassUnderTest cut= new ClassUnderTest(180000);
        cut.sendToEventBusAddress(routingContext, "testRequestId", "UnitTestId");
        verify(contextResponse).setStatusCode(200);
    }
}

我知道当前形式的测试将无法正常工作,因为被测方法会在方法内部调用eventBus()。send()方法后立即返回,因此,验证失败并显示'no互动”。

鉴于Vertx的异步特性,我不知道要如何正确验证它!

谢谢

1 个答案:

答案 0 :(得分:0)

我是这样做的:

  1. 在带有@BeforeAll的批注方法中,我仅部署了发送Verticle。

  2. @BeforeEach处-我为给定消息创建使用者,并将消息存储到变量/集合

    类似的东西:

    receivedMessage = new Message[1];
       eventBus.consumer("DB",
            message -> {
                message.reply("OK");
                receivedMessage[0] = message;
            });
    context.completeNow();
    
  3. 在测试中,我验证存储的值:

    client.get(8080, "localhost", "/user/" + id)
        .as(BodyCodec.string())
        .send(context.succeeding((response -> context.verify(() -> {
            Assertions.assertEquals(expectedMessage, receivedMessage[0].body());
            context.completeNow();
    }))));