如何对这个线程代码进行单元测试

Hil*_*kus 0 java multithreading unit-testing mockito

我有一个类通常在一个线程中运行,该线程永远处理数据,直到另一个线程调用它的stop().我遇到的问题是单元测试卡在主循环中,因为测试是单线程的,我想保持这种方式.如何在不污染代码的情况下对其进行单元测试?这个类是关键系统的一部分,需要尽可能简单有效,所以我想避免代码中的单元测试黑客

public class MyClass implements Runnable {

   boolean running;

   public void run() {
      //foo is injected from the outside
      foo.start();
      work();
      foo.end();
   }

   public void work() { 
      running = true;
      while(running) { //main loop
         bar.process(); //bar is injected from the outside
      }
   }

   public void stop() {
      running = false;
   }
}
Run Code Online (Sandbox Code Playgroud)

基本上我在测试中做的是嘲笑foobarrun()从单元测试中调用,后来我在bar中验证是否process实际调用了.我还验证了在foo模拟start()end()被调用.问题是因为我真的想保持测试单线程,测试线程永远陷入while(running)循环中.

我尝试过但不喜欢的一些事情

  • 添加一些VM属性以在主循环的迭代结束时触发中断.这样做的问题在于,如上所述,这段代码非常关键,我希望保持代码不受单元测试混乱的影响.我不希望生成代码在每次迭代中评估一些我在开发时仅使用的VM属性
  • 使用bar mock来调用stop()process().Mockito不喜欢我调用另一个类'方法并抛出异常的事实
  • 外化主循环的控制.所以我没有检查while中的布尔值,而是调用一个返回是否继续的方法.并且这个循环控制对象可以从外部注入,这样在单元测试中我可以使控制方法返回true然后返回false以从循环中获得单个迭代.这会使代码变得非常复杂,并使其不自然且难以阅读,而且只在单元测试环境中才有意义

是否有任何其他建议或常用模式来测试Runnables,或者更好的方法来编写我的代码以便更容易测试?

Wil*_*son 5

我建议进行一项更改,这将使您的代码更多地通过书本允许在单个线程中突破:

while (!Thread.currentThread().isInterrupted() && running) {
     bar.process();
  }
Run Code Online (Sandbox Code Playgroud)

您可以Thread.currentThread().interrupt()在运行此代码之前调用; 线程的interrupted标志将被设置,方法isInterrupted()将返回true.

这更像是一本书,因为它使你的主循环参与Java的中断机制.