2011-09-29 143 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 –