2011-09-29 184 views
5

下面是我的應用程序的簡化設置。它有一個Foobar類,它調用一個外觀方法來獲取數據。然後,外觀調用Web服務來實際獲取數據,然後稍微處理數據,然後將其返回給Foobar。測試一個異步方法調用

現在因爲Web服務可能持續較長一段時間的運行,該方法調用的門面需要是異步的。因此,Facade的方法沒有返回值,而是使用回調對象。看看這個例子,並繼續閱讀下面。

public class Foobar { 
    private List<DTO> dtos; 

    @Autowired 
    private Facade facade; 

    public void refresh() { 
     facade.refreshFoobar(new CallBack() { 
      public void dataFetched(List<DTO> dtos) { 
       setDtos(dtos); 
      } 

     }); 
    }  

    public void setDtos(List<DTO> dtos) { 
     this.dtos = dtos; 
    } 
} 


public class Facade { 

    ... 

    public void refreshFoorbar(CallBack cb) { 
     // Fetch data from a web service 
     List<DTO> dtos = webService.getData(); 
     // Manipulate DTOs 
     .... 
     // call on the callback method 
     cb.dataFecthed(dtos); 
    } 

} 

我有兩種使Facade的方法異步的方法,無論是通過手動創建線程還是使用springs @Async註釋。

public class Facade { 

    public void refreshFoorbar(CallBack cb) { 
     new Thread() { 

      @Override 
      public void run() { 
       .... 
      } 

     }.start(); 

    } 
} 

// ... OR ... 

public class Facade { 

    @Async 
    public void refreshFoorbar(CallBack cb) { 
     ....  
    } 
} 

我的問題是,我現在需要爲這個方法調用鏈寫一個集成測試。我認爲我需要強制異步門面調用在集成測試運行時同步,否則當我可以執行適當的斷言時我無法確定。用於製備方法調用同步的唯一想法是使用手工處理線程和使穿線條件(因此,用於測試目的,我有一個if語句,它確定是否門面方法應在一個單獨的線程來運行或沒有)。

但是,我有一種感覺,可能有更好的解決方案來解決我的問題,無論是強制方法對我來說是同步的更好方式,例如使用spring,還是通過在某種方式上測試多線程。

這是我需要你的建議,你將如何解決我的問題?請注意,我正在使用junit進行單元測試和集成測試。

+0

我不知道這是否是正確的方法。通常,對異步條件進行測試只是啓動異步任務,等待一段時間並測試任務是否已完成。 – SJuan76

回答

6

當JUnit測試這樣的東西時,我使用了一個測試回調,其中CountDownLatch由測試方法編寫的回調和await()編寫。

private static class TestingCallback implements Callback { 
    private final CountDownLatch latch; 
    public TestingCallback(CountDownLatch latch) { 
     this.latch = latch; 
    } 
    @Override public void onEvent() { 
     this.latch.countDown(); 
    } 
} 

@Test 
public void testCallback() { 
    final CountDownLatch latch = new CountDownLatch(1); 

    classUnderTest.execute(new TestCallback(latch)); 

    assertTrue(latch.await(30, TimeUnit.SECONDS)); 
} 

如果回調由被測代碼調用(異步地),閂鎖返回true和測試通過。如果回調未被調用,則測試在三十秒後超時並且斷言失敗。

12

簡單的解決辦法是將返回一個Future對象這樣,

@Async 
public Future<String> refreshFoorbar(CallBack cb) { 
    yourHeavyLifting(); //asynchronous call 
    return new AsyncResult<String>("yourJobNameMaybe"); 
} 

並在測試,以備將來參考,並調用get()方法。

future.get(); // if its not already complete, waits for it to complete 
assertTrue(yourTestCondition) 

這個blog post顯示一個樣本。

+0

看到這是否有幫助http://www-01.ibm.com/support/knowledgecenter/SSCKBL_8.5.5/com.ibm.websphere.nd.multiplatform.doc/ae/tejb_clientcode.html –