2012-06-19 2 views
8

비동기 메소드가 있습니다. 카운트 다운 래치를 사용하는 동기화 메소드로 변환 중입니다. mockito의 타임 아웃 기능을 사용하지 않고 단위 테스트를 작성하는 데 어려움을 겪고 있습니다. 나는 확인 방법은 비동기 메서드 호출을 기다리는 방법을 알아 작동하지 않을 수 있습니다Java async-> sync converter가있는 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); 
    } 


} 

답변

2

에서 호출되었는지 확인합니다 있도록 여러 번 실행해야 나는 awaitility이라는 작은 라이브러리를 사용하고 싶습니다. 카운트 다운 래치로 직접 할 수 있지만 보았 듯이 벌레로 그 테스트를 해킹해야합니다.

이 테스트에서는 래치를 기다렸다가 확인을해야합니다.

코드의 또 다른 문제점은 private Boolean response입니다. 다른 스레드에서 변경하기 때문에 AtomicBoolean을 작성하거나 적어도 volatile이라고 선언해야합니다.

+1

+1을 작성하는 것이 도움이 될 수 있습니다. 나는 그것에 대해 들어 보지 못했지만 아주 유용하게 보입니다. – jhericks

-1

내가 제대로 이해 모르겠어요. 한 스레드가 다른 스레드가 무언가를 수행 할 때까지 무한정 기다리는 것을 테스트하고 싶은 경우에는 수행 할 수 없다고 말합니다. 프로그램 종료 여부를 묻는 것입니다. 대신에 두 가지 일을 할 수 있습니다.

  1. 정기적 인 동시 테스트를 수행합니다 (정의 상으로는 임의적이며 코드가 정확한지 확실하지 않습니다). 자물쇠를 사용하는 두 개의 스레드로 복잡한 테스트를 만들고 서비스를 시뮬레이트하고 yeld() 메소드를 사용합니다. 중요한 섹션에서 잘못된 순서가 없는지 테스트 할 수 있습니다. 물론 당신은, CountDownLatch를가 제대로 작동한다고 가정하면
  2. 10ms 이상의을 그것을 조롱하고 테스트의 이러한 종류의 기능이 올바른 순서
+0

나는 당신이 무엇을 얻고 있는지 확실히 모르겠다. 나는 위의 클래스를 테스트하는 결정 론적 방법을 찾고있다. 즉 한 번 또는 수백만 번 실행했는지 여부에 관계없이 항상 동일한 결과를 산출합니다. 현재 경쟁 조건이 있으므로 실패 할 수 있습니다. –

+0

또한 클래스를 재구성하지 않고도 CountDownLatch를 종속물로 전달되지 않기 때문에 조롱 할 수 없습니다. 내 포인트는 –

+0

입니다. 결정적인 방법으로 멀티 스레드 코드를 테스트 할 수는 없습니다. '맞습니다'. 한 스레드가 다른 스레드 [http://en.wikipedia.org/wiki/Halting_problem]까지 기다릴지를 테스트 할 수 없습니다. 물론 countDownLatch를 모의 할 수 있습니다. powermock 및 whitebox를 참조하십시오. – piotrek