如何jUnit测试另一个线程中的代码结果

时间:2011-04-03 18:36:00

标签: java multithreading junit

我有一个在线程中运行的进程(用作实时信号分析过程)。我想为该线程进程提供已知输入,然后在jUnit中测试输出是否正确。我有一个回调监听器,可以在线程完成数据处理时通知我,并且可以通过将测试用例本身注册为监听器来成功运行对结果的断言。
   当这些断言失败时,它们会抛出异常。但是这个异常并没有被jUnit注册为失败,大概是因为它们发生在测试方法之外。

如何构建我的jUnit测试,以便在侦听器返回后测试失败?这是代码的简化版本。

 public class PitchDetectionTest extends TestCase 
    implements EngineRunCompleteListener() {
  AudioData            fixtureData;
  PitchDetectionEngine pitchEngine;

  public void setUp() {
    fixtureData = <stuff to load audio data>;
  }

  public void testCorrectPitch() {
    pitchEngine = new PitchEngine(fixtureData);
    pitchEngine.setCompletionListener(this);
    pitchEngine.start();   
    // delay termination long enough for the engine to complete
    try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
  }

  // gets called by the PitchEngine when it has finished processing all data in the
  // fixtureData.   This is the only method defined by interface    
  // EngineRunCompleteListener.
  public void notifyEngineRunComplete() {

    // The real code asserts things about the PitchEngine's results.   When they fail, 
    // an exception is thrown that I can see in the console, but this unit test still  
    // shows as 'success' in the jUnit interface.   What I want is to see 
    // testCorrectPitch() fail.
    assertTrue(false);  

  }

}

public class PitchEngine () {
  EngineRunCompleteListener completionListener();
  Thread myThread;

  public void start() {
    // other stuff
    myThread = new Thread(this);
    myThread.start();    
  }

  public void run() {
    while (some condition) {
      // do stuff with the data
    }
    if (engineRunCompleteListener != null) {
      engineRunCompleteListener.notifyEngineRunComplete();
    }
  }

}

5 个答案:

答案 0 :(得分:9)

您已经有两个线程在运行。您的junit线程和进程线程(由myThread.start()启动 在我的头脑中,我可以想到至少有两个选项,所有这些选项都涉及将断言从notifyEngineRunComplete移开。例如:

  • 您可以使用join等待进程线程完成,然后执行断言(Javadoc here)。
  • 您可以通过等待监视器对象将您的junit线程置于休眠状态,然后在您的回调函数中通知此监视器。这样你就会知道这个过程已经完成了。
  • 您可以使用ExecutorFuture对象。我认为如果它适用于您的类(Javadoc here),这将是最酷的解决方案。

答案 1 :(得分:2)

测试线程/异步代码的一般方法是阻塞主测试线程,从其他线程(例如调用侦听器的线程)捕获任何失败的断言,取消阻塞主测试线程以及抛出和失败的断言。 ConcurrentUnit使这非常简单:

final Waiter waiter = new Waiter();

bus.registerListener(() -> {
  // Perform assertion in some other thread
  waiter.assertTrue(true);
  waiter.resume();
});

// Wait for resume() to be called
waiter.await(5000);

答案 2 :(得分:1)

  

我想为该线程进程提供已知输入,然后在jUnit中测试输出是否正确。我有一个回调监听器,可以在线程完成数据处理时通知我,并且我可以通过将测试用例本身注册为监听器来成功运行对结果的断言。

为什么不在PitchEngine中将//do stuff with the data逻辑提取到另一个公共方法,而只是在单元测试中调用它,而不是在单元测试中为PitchEngine启动一个单独的线程?我想不出任何理由在单元测试中实际生成线程,因为听起来你真正关心的(在这个单元测试中)正在测试处理逻辑。

答案 3 :(得分:1)

如果必须在回调中运行断言代码,请将回调方法包装在try catch中。捕获任何throwable并有一种方法将该异常传递回junit线程(某种共享线程状态)。然后junit线程重新抛出任何返回的throwable。

答案 4 :(得分:0)

如果您只有一个要执行断言的工作线程,则

join()有效。如果您有多个线程需要将断言报告回主线程,则需要使用其他一些机制。请查看ConcurrentUnit