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

Java 如何在另一个线程中jUnit测试代码的结果,java,multithreading,junit,Java,Multithreading,Junit,我有一个在线程中运行的进程(用作实时信号分析进程)。我想为该线程进程提供一个已知的输入,然后在jUnit中测试输出是否正确。我有一个回调监听器,它可以在线程完成数据处理时通知我,并且我可以通过将测试用例本身注册为监听器来成功地对结果运行断言。 当这些断言失败时,它们会抛出异常。但是jUnit没有将该异常注册为失败,可能是因为它们发生在测试方法之外 如何构造jUnit测试,以便在侦听器返回后测试正确失败?下面是代码的简化版本 public class PitchDetectionTest ext

我有一个在线程中运行的进程(用作实时信号分析进程)。我想为该线程进程提供一个已知的输入,然后在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();
    }
  }

}
公共类PitchDetectionTest扩展了TestCase
实现EngineRunCompleteListener(){
音频数据固定数据;
沥青检测发动机沥青发动机;
公共作废设置(){
fixtureData=;
}
公共无效测试校正间距(){
pitchEngine=新的pitchEngine(fixtureData);
pitchEngine.setCompletionListener(此);
pitchEngine.start();
//延迟终止时间足以使发动机完成
尝试{Thread.sleep(1000);}catch(InterruptedException e){e.printStackTrace();}
}
//当PitchEngine处理完
//这是接口定义的唯一方法
//EngineRunCompleteListener。
public void notifyEngineRunComplete(){
//真正的代码断言了PitchEngine的结果。当它们失败时,
//抛出了一个异常,我可以在控制台中看到,但是这个单元测试仍然存在
//在jUnit界面中显示为“成功”。我想看到的是
//testCorrectPitch()失败。
资产真(假);
}
}
公共级沥青发动机(){
EngineRunCompleteListener completionListener();
线程读取;
公开作废开始(){
//其他东西
myThread=新线程(此线程);
myThread.start();
}
公开募捐{
虽然(某些条件){
//处理数据
}
如果(engineRunCompleteListener!=null){
engineRunCompleteListener.notifyEngineRunComplete();
}
}
}

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

  • 您可以使用
    join
    等待进程线程完成,然后执行断言(Javadoc)
  • 您可以通过等待监视器对象使junit线程进入睡眠状态,然后在回调函数中通知此监视器。这样您就知道进程已经完成
  • 您可以使用
    Executor
    Future
    对象。我认为如果它与您的类(Javadoc)一起使用,这将是最酷的解决方案
我希望为该线程处理一个已知的输入,然后在jUnit中测试输出是否正确。我有一个回调侦听器,它可以在线程完成数据处理时通知我,并且我可以通过将测试用例本身注册为侦听器来成功地对结果运行断言


与其在单元测试中为
PitchEngine
启动一个单独的线程,为什么不将
//将
PitchEngine
中的数据逻辑提取到另一个公共方法中,并在单元测试中简单地调用它呢?我想不出任何理由在单元测试中实际生成线程,因为它听起来很简单在这个单元测试中,您真正关心的是测试处理逻辑。

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

join()
在只有一个工作线程要从中执行断言的情况下有效。如果有多个线程需要将断言报告回主线程,则需要使用其他机制。请检查该机制。

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

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);

这将是一个伟大的想法与简化版本,我已经向你展示了在这里-不幸的是,在这种情况下运行“做的东西”在引擎中,需要连接一组数据处理对象并管理它们的交互。它依赖于PitchEngine中的几种方法以及它的超类中的几种方法,并且不容易提取。我可以看到一些改进模块化的方法,但它们比我现在花的时间要多。你看过了吗在你的
PitchingineTest
中用mock替换那些其他对象?在这里使用mock没有帮助;我尝试编写的测试是对音高引擎的全堆栈测试,确认它检测到正确的音高,给定一个音频波形样本。我需要所有实际运行的代码。这可能有用-join()是我们最终使用的解决方案。我必须向engine类添加一个方法以返回其线程,这感觉有点不舒服,因为这意味着向类添加方法纯粹是为了测试它们,但它非常简单,而且有效。感谢您的建议。您可以向engine类添加一个名为
joime()的方法
或类似的东西,执行相同的功能。这样,单元测试线程可以等待引擎完成,而不知道其内部线程。您还应该考虑