如何处理 JUnit 测试用例中的 wait() 方法调用?



我有一个方法,它有另一个方法调用,其定义有一个SomeIntegerObject.wait()调用。现在,当我运行测试用例时,由于这种等待方法,测试用例会一直等待并且不执行。

我尝试在注释中添加超时@Test但这会导致"测试超时"之类的异常。

测试方法:

private PastingResult result;
public PastingResult pasteImages(IIOImage[] images, byte pasteProcessType){
result = new PastingResult();
_reprocessingProvider.setListLogicHandler(this);
//--some more method calls--
waitForResult(); //causes my test case to wait forever and pauses execution
return result;
}

测试用例:

@Test
public void testPasteImagesIIOImageArrayByte() throws Exception 
{
ReprocessManager _reprocessingProvider1=Mockito.mock(ReprocessManager.class);
Whitebox.setInternalState(imagePasterIfImpl, "_reprocessingProvider", _reprocessingProvider1);
IIOImage[] images=new IIOImage[]{Mockito.mock(IIOImage.class),Mockito.mock(IIOImage.class)};
byte pasteProcessType = 02;
PastingResult result= imagePasterIfImpl.pasteImages(images, pasteProcessType);  
Mockito.verify(_reprocessingProvider1).setListLogicHandler(imagePasterIfImpl);
System.out.println(result+"is the result");
}

waitForResult();的定义

private Integer processingWaitMonitor = new Integer(0);
private void waitForResult() {
// synchronize to wait on the Monitor..
synchronized(processingWaitMonitor) {
try {
processingWaitMonitor.wait();
}
catch(Exception e) {
System.out.println("Exception during Wait !"+e);
}
}
}

这里有两个答案:

  • 在第一個層次上:如果你需要控制被測物體內部的東西;你可以求助於Mockito Spys或PowerMock或JMockit;因為這些框架允許在這些方面進行"mock"(也就是獲得控制)。但在大多数情况下,这并不是真正的好做法;如果有的话,你应该将所需的功能"外包"到另一个类中;然后使用依赖关系注入,以便为测试设置提供该类的模拟对象。而不是真正的等待,你只需在一个模拟的对象上调用一些等待方法,它什么都不做。
  • 除此之外:你可以退后一步,考虑重新设计你的整个方法。你看,使用那些"低级"原语(如等待/通知)不再是的做法。有抽象,如ExecutorService,Futures,Promises。关键是:使用 ExecutorService,您可以重写代码以使用 Same-Thread-Executor-Service 进行测试。意思是:可以重写多线程代码,这样只需为测试提供不同的执行器,所有事情都可以在单个线程上运行。不再需要等待,保证,可靠的结果。

关于你的评论;你的代码说:

private Integer processingWaitMonitor = new Integer(0);
private void waitForResult() {

意思是:你在测试的类中有一个字段+私有方法。假设您创建

public interface<E> WaitService {
public E waitForResult();
}

或类似的东西。然后;而不是在生产类中有一个锁定对象和该 wait 方法,您只需将该服务的"某个"实例保留在那里。但是,当然,这再次要求您更改生产代码。

如果你真的不能改变那个代码(这有点可惜 - 当你不能改变代码时,测试代码有什么意义?那么Mockito/PowerMock/JMockit是你到达那里的唯一选择。

正在等待的模块,将其放入 junit 测试用例中的新线程中。间隔后,检查线程是否完成。设置间隔的最大超时。发生超时后,检查线程完成情况,并决定是要通过还是失败。

例如:

private static final int MAX_WAIT_TIME = 20000; //total time out in milliseconds
private static final int WAIT_INTERVAL = 1000; //wait interval till MAX_WAIT_TIME
@Test
public void testPasteImagesIIOImageArrayByte() throws Exception 
{
Thread t = new MyThread();
t.start();    
int totalWaitTime = 0;
while ((!t.isCompleted()) && totalWaitTime <= MAX_WAIT_TIME) {
try {
totalWaitTime += WAIT_INTERVAL;
Thread.sleep(WAIT_INTERVAL);
} catch (java.lang.InterruptedException e) {
//LOG OR THROW
}
if(!t.isCompleted()){
if(t.hasExceptionOccurred()){
//fail the case
}else{
//take your decision here, if you want to pass it or fail it
}
}
}
}
class MyThead extends Thread{
private volatile boolean isCompleted = false;
private volatile Throwable exception = null;
private volatile boolean hasExceptionOccured = false;
public void run(){
try{
ReprocessManager _reprocessingProvider1=Mockito.mock(ReprocessManager.class);
Whitebox.setInternalState(imagePasterIfImpl, "_reprocessingProvider", _reprocessingProvider1);
IIOImage[] images=new IIOImage[]{Mockito.mock(IIOImage.class),Mockito.mock(IIOImage.class)};
byte pasteProcessType = 02;
PastingResult result= imagePasterIfImpl.pasteImages(images, pasteProcessType);  
Mockito.verify(_reprocessingProvider1).setListLogicHandler(imagePasterIfImpl);
System.out.println(result+"is the result");
synchronized(this){
isCompleted = true;
}
}catch(Throwable ex){
synchronized(this){
exception = ex;
hasExceptionOccured = true;
}
}
}
public synchronized boolean isCompleted(){
return isCompleted;
}
public synchronized boolean hasExceptionOccurred(){
return hasExceptionOccured;
}
public synchronized Throwable getExceptionOccurred(){
return exception;
}
}

最新更新