如何解决这种典型的生产者消费者方案

时间:2014-12-24 09:50:03

标签: java synchronization integration-testing testng

我遇到了一个interresting,我认为我的测试代码中存在非常常见的同步问题。

这是测试(它是从外部连接到系统的功能测试),我是通过TestNG运行的。

@Test
public void operationalClientConnected_sendGetUserSessionRequest_clientShallReceiveGetUserSessionResponse() {
    // GIVEN
    OperationalClientSimulator client = operationalClientHasEstablishedWebSocketConnection("ClientXY");

    // WHEN
    GetUserSessionRequest request = PojoRequestBuilder.newRequest(GetUserSessionRequest.class).build();
    client.sendRequest(request);

    // THEN
    assertThatClientReceivesResponse(client, GetUserSessionResponse.class, request.getCorrelationId(), request.getRequestId());
}

基本上我发送一个请求并等待正确的响应,这是我想在此测试中验证的内容。

assertThatClientReceivesResponse后面有一个看起来像这样的hamcrest匹配器:

@Override
protected boolean matchesSafely(final OperationalClientSimulator client) {
    Object awaitedMessage = client.awaitMessage(
            new Verification<Object>() {
                @Override
                public VerificationResult verify(final Object actual) {
                    VerificationResult result = new VerificationResult();

                    if (!_expectedResponseClass.isInstance(actual)) {
                        result.addMismatch("not of expected type", actual, _expectedResponseClass.getSimpleName());
                    }

                    // check more details of message ..   

                    return result;
                }
            }, _expectedTimeout);

    boolean matches = awaitedMessage != null;
    if (matches) {
        _messageCaptor.setActualMessage((T) awaitedMessage);
    }

    return matches;
}

现在对于interresting部分,OperationalClientSimulator类中的同步。 有两种方法可以解决:

  1. awaitMessage会阻塞,直到收到与给定验证匹配的邮件或超时已过期

  2. onMessage收到的方法,为每个收到的消息(通过websocket连接)调用

  3. 基本上我想要实现的是在awaitMessage方法上使用测试线程块,直到收到正确的消息(通过onMessage)或指定的超时时间为止。

    public Object awaitMessage(final Verification<Object> verification, final long timeoutMillis) {
        // howto sync?
        return awaitedMessage; // or null
    }
    
    @Override
    public void onMessage(final String message) {
        LOG.info("#Client {} <== received a message on websocket - {}", name, message);
        // howto sync?
    }
    

    关于测试:

    • 测试线程几乎总是更快,因此必须等到通过awaitMessage方法收到响应
    • 在测试线程检查之前收到预期消息的情况非常罕见(这基本上意味着我必须保存每个收到的消息)
    • 在这个特定的测试用例中,只收到了一小撮消息(一些心跳消息,实际响应和通知),但在其他情况下,可能有数百条消息需要检查才能找到预期的消息(多个)消息

    我在考虑不同的同步解决方案:

    1. 最简单的当然是与synchronized关键字同步,但我认为有更简洁的方法可以做到这一点
    2. onMessage收到的方法可以简单地写入阻塞队列,测试线程可以从中消耗,但在这里我不知道如何测量超时...我可以使用CountdownLatch吗?
    3. 也许我可以做一个非阻塞解决方案,其中生产者(onMessage)写入数组并且消费者读取直到它到达生产者发布的索引(如LMAX Disruptor)
    4. 我知道这是测试代码并且性能在这里不是真正的问题,我只是在考虑如何以“漂亮”的方式解决这个问题..你知道..因为它的圣诞节: - )

      所以这里的实际问题是,我如何“安全”地等待我在测试中超时的消息?安全地这意味着我不会因为并发问题而错过消息或丢失消息,而且我还需要检查是否已收到预期的消息。

      当在websocket连接上收到消息时,我应该如何在测试运行程序线程和onMessage中调用OperationalClientSimulator方法的线程之间进行同步。

0 个答案:

没有答案