Java 单元测试在调试模式下成功,但在正常运行时失败

Java 单元测试在调试模式下成功,但在正常运行时失败,java,multithreading,junit,future,callable,Java,Multithreading,Junit,Future,Callable,为什么我的单元测试在调试模式下成功,但在正常运行时失败 public class ExecutorServiceTest extends MockitoTestCase{ private int numThreads; private ExecutorService pool; private volatile boolean interruptedBitSet; @Override public void setUp() { numThreads = 5;

为什么我的单元测试在调试模式下成功,但在正常运行时失败

public class ExecutorServiceTest extends MockitoTestCase{   
  private int numThreads;
  private ExecutorService pool;
  private volatile boolean interruptedBitSet;

  @Override
  public void setUp() {
    numThreads = 5;
    pool = Executors.newFixedThreadPool(numThreads);
  }

class TaskChecksForInterruptedBit implements Callable<String> {
    @Override
    public String call() throws Exception {
      interruptedBitSet = false;
      while (!Thread.currentThread().isInterrupted()) {
      }
      interruptedBitSet = Thread.currentThread().isInterrupted();
      return "blah";
    }
  }

public void testCancelSetsInterruptedBitInCallable() throws Exception {
    interruptedBitSet = false;
    final Future<String> future = 
        pool.submit(new TaskChecksForInterruptedBit());
    final boolean wasJustCancelled = future.cancel(true);
    assertTrue(wasJustCancelled);

    // Give time for the thread to notice the interrupted bit and set the flag
    Thread.sleep(5000);

    // This succeeds when stepping through w/ a debugger, but fails when running
    // the test straight. WHY?
    assertTrue(interruptedBitSet);

    assertTrue(future.isDone());
    assertTrue(future.isCancelled());
  }
}
公共类ExecutorServiceTest扩展了MockitoTestCase{
私有int numThreads;
私人服务池;
私有易失性布尔中断位集;
@凌驾
公共作废设置(){
numThreads=5;
pool=Executors.newFixedThreadPool(numThreads);
}
类TaskChecksForentErrorUptedBit实现可调用{
@凌驾
公共字符串调用()引发异常{
interruptedBitSet=false;
而(!Thread.currentThread().isInterrupted()){
}
interruptedBitSet=Thread.currentThread().isInterrupted();
返回“废话”;
}
}
public void testCancelSetsInterruptedBitInCallable()引发异常{
interruptedBitSet=false;
最终未来=
提交(新任务检查PrinterUptedBit());
最终布尔值wasJustCancelled=future.cancel(true);
资产真实(刚刚取消);
//让线程有时间注意到中断位并设置标志
睡眠(5000);
//这在单步执行w/a调试器时成功,但在运行时失败
//考试很简单,为什么?
assertTrue(中断位集);
assertTrue(future.isDone());
assertTrue(future.isCancelled());
}
}

原因几乎可以肯定是调试器中的断点正在停止主线程,而不是任何后台线程,即ExecutorService中的线程。在eclipse中调试时,您可以更改断点以停止所有线程,而不仅仅是主线程

当不调试任务时,任务的提交和立即取消是如此之快,以至于在任务运行一次之前就取消了任务。尝试在以下行之间添加睡眠延迟:

final Future<String> future =  pool.submit(new TaskChecksForInterruptedBit());
Thread.sleep(1000);
final boolean wasJustCancelled = future.cancel(true);
final Future=pool.submit(新任务检查forterruptedbit());
睡眠(1000);
最终布尔值wasJustCancelled=future.cancel(true);

您必须确保任务实际开始运行。它可能在有机会之前就被取消了

public class ExecutorServiceTest {
    private int numThreads;
    private ExecutorService pool;
    private volatile boolean interruptedBitSet;
    private static final CountDownLatch latch = new CountDownLatch(1);

    @Before
    public void setUp() {
        numThreads = 5;
        pool = Executors.newFixedThreadPool(numThreads);
    }

    class TaskChecksForInterruptedBit implements Callable<String> {
        @Override
        public String call() throws Exception {
            interruptedBitSet = false;
            latch.countDown();
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println(System.currentTimeMillis());
            }
            System.out.println("haha");
            interruptedBitSet = Thread.currentThread().isInterrupted();
            return "blah";
        }
    }

    @Test
    public void testCancelSetsInterruptedBitInCallable() throws Exception {
        final Future<String> future =
                pool.submit(new TaskChecksForInterruptedBit());
        interruptedBitSet = false;
        latch.await();
        final boolean wasJustCancelled = future.cancel(true);
        Assert.assertTrue(wasJustCancelled);

        // Give time for the thread to notice the interrupted bit and set the flag
        Thread.sleep(5000);

        // This succeeds when stepping through w/ a debugger, but fails when running
        // the test straight. WHY?
        Assert.assertTrue(interruptedBitSet);

        Assert.assertTrue(future.isDone());
        Assert.assertTrue(future.isCancelled());
    }
}
公共类执行器服务测试{
私有int numThreads;
私人服务池;
私有易失性布尔中断位集;
专用静态最终倒计时闩锁=新倒计时闩锁(1);
@以前
公共作废设置(){
numThreads=5;
pool=Executors.newFixedThreadPool(numThreads);
}
类TaskChecksForentErrorUptedBit实现可调用{
@凌驾
公共字符串调用()引发异常{
interruptedBitSet=false;
倒计时();
而(!Thread.currentThread().isInterrupted()){
System.out.println(System.currentTimeMillis());
}
System.out.println(“哈哈”);
interruptedBitSet=Thread.currentThread().isInterrupted();
返回“废话”;
}
}
@试验
public void testCancelSetsInterruptedBitInCallable()引发异常{
最后的未来=
提交(新任务检查PrinterUptedBit());
interruptedBitSet=false;
satch.wait();
最终布尔值wasJustCancelled=future.cancel(true);
Assert.assertTrue(wasJustCancelled);
//让线程有时间注意到中断位并设置标志
睡眠(5000);
//这在单步执行w/a调试器时成功,但在运行时失败
//考试很简单,为什么?
Assert.assertTrue(中断位集);
Assert.assertTrue(future.isDone());
Assert.assertTrue(future.isCancelled());
}
}

我知道这很旧,但我也有同样的问题。 我的问题是我有一个IEnumerable,我正在枚举和检查输出

运行单元测试时,IEnumerable返回的顺序与调试时不同。这就是IEnumerable的本质,简单地添加一个OrderBy子句就解决了我的问题


我希望这对其他人有所帮助,因为这可能是一个令人沮丧的问题。

在终止主线程之前,您应该检查是否所有线程都已死亡

private void shutdownExecutionService(ExecutorService executorService) {
    if (executorService != null) {
        try {
            executorService.shutdown();
            while (!executorService.awaitTermination(10, TimeUnit.HOURS)) {
                logger.info("Awaiting completion of threads.");
            }
        } catch (final InterruptedException e) {
            logger.error("Error while shutting down threadpool", e);
        }
    }
}

我在网上做作业时也遇到了类似的问题。我添加到构建路径的课程中的grader程序使用JUnit4,我的Eclipse版本将JUnit5添加到任何新的测试用例中。我已经创建了一个新的Java项目,并在没有分级器的情况下为我的测试用例将JUnit5添加到构建池中,它为我修复了它。希望这有帮助。

建议,试着使
中断位集
易失性
调试时断点在哪里?@Alb我将其设置为“interruptedBitSet=false;”为什么主线程在发布模式下看不到修改标志(由派生线程修改)?让我澄清一下:我在测试方法中将其设置为“interruptedBitSet=false”,而不是可调用的call()方法。@Chris Morris抱歉,我先误读了代码,我用另一个建议编辑了我的答案,
reflections.getSubsof(Foo.class)
运行/调试时的顺序不同