9

我有一个异步方法,我正在使用倒计时锁存器转换为同步方法。我在不使用 mockito 的超时功能的情况下努力编写单元测试。我不知道如何让验证方法等待异步方法调用:

public interface SyncExchangeService {
    boolean placeOrder(Order order);
}
public interface ExchangeService {
    void placeOrder(Order order, OrderCallback orderResponseCallback);
}

public interface OrderCallback {
    public void onSuccess();
    public void onFailure();
}



public class SyncExchangeServiceAdapter implements SyncExchangeService {
    private ExchangeService exchangeService;

    public SyncExchangeServiceAdapter(ExchangeService exchangeService) {
        this.exchangeService = exchangeService;
    }

    @Override
    public boolean placeOrder(Order order) {

        final CountDownLatch countdownLatch=new CountDownLatch(1);
        final AtomicBoolean result=new AtomicBoolean();
        exchangeService.placeOrder(order, new OrderCallback() {

            @Override
            public void onSuccess() {
                result.set(true);
                countdownLatch.countDown();
            }

            @Override
            public void onFailure(String rejectReason) {
                result.set(false);
                countdownLatch.countDown();
            }
        });
        try {
            countdownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return result.get();
    }
}


public class SyncExchangeServiceAdapterTest {
    private ExchangeService mockExchange=mock(ExchangeService.class);
    private SyncExchangeServiceAdapter adapter=new SyncExchangeServiceAdapter(mockExchange);
    private Boolean response;
    private ArgumentCaptor<Boolean> callback=CaptorArgumentCaptor.forClass(OrderCallback.class);
    private CountDownLatch latch=new CountDownLatch(1);


    @Test
    public void testPlaceOrderWithSuccess() throws Exception {
        final Order order=mock(Order.class);
         Executors.newSingleThreadExecutor().submit(new Runnable() {
            @Override
            public void run() {
                response=adapter.placeOrder(order);
                latch.countDown();
            }
        });
            verify(mockExchange,timeout(10) ).placeOrder(eq(order), callbackCaptor.capture());
//the timeout method is not really recommended and could also fail randomly if the thread takes more than 10ms


        callbackCaptor.getValue().onSuccess();
        latch.await(1000,TimeUnit.MILLISECONDS);
            assertEquals(true,response);
    }


}
4

2 回答 2

3

对于这些类型的测试,我喜欢使用一个名为awaitility的小库。您可以使用倒计时闩锁自己完成,但正如您所看到的,您必须用砍刀破坏您的测试才能完成这项工作。

在此测试中,您应该在等待闩锁后调用 verify。

您的代码中的另一个问题是private Boolean response. 由于您要在另一个线程中更改它,因此您应该将其设为AtomicBoolean或至少声明它volatile

于 2012-07-23T04:53:06.027 回答
-1

我不确定我是否理解正确。如果你想测试一个线程无限期地等待直到另一个线程做某事,那么我会说你做不到。因为这意味着您正在询问程序是否终止。相反,您可以做两件事。

  1. 定期进行并发测试(根据定义,它是随机的,并且不能确定代码是否正确)。您使用两个线程创建复杂的测试,这些线程使用锁并模拟服务并使用 yeld() 方法。在关键部分,您可以测试是否没有错误的顺序。当然你必须运行它很多次,所以它会花费你超过 10 毫秒
  2. 假设 CountDownLatch 正常工作,模拟它并检查它的函数是否以正确的顺序调用
于 2012-06-20T20:03:36.453 回答