【问题标题】:Unit test succeeds in debug mode but fails when running it normally单元测试在调试模式下成功,但在正常运行时失败
【发布时间】:2013-02-16 15:00:38
【问题描述】:

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

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

【问题讨论】:

  • 建议,尝试制作interruptedBitSet volatile
  • 你调试的时候断点在哪里?
  • @Alb 我把它放在'interruptedBitSet = false;'

标签: java multithreading junit future callable


【解决方案1】:

我在运行在线课程的家庭作业时遇到了类似的问题。我添加到构建路径的课程中的分级程序使用了 JUnit4,我的 Eclipse 版本将 JUnit5 添加到任何新的测试用例中。我创建了一个新的 Java 项目,并将 JUnit5 添加到我的测试用例的构建浴中,没有评分器,它为我修复了它。希望这会有所帮助。

【讨论】:

    【解决方案2】:

    你应该在终止主线程之前检查所有线程是否都死了

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 知道了,reflections.getSubTypesOf(Foo.class) 在运行/调试中的顺序不同
      【解决方案4】:

      原因几乎可以肯定是调试器中的断点暂停了主线程,但没有暂停任何后台线程 - ExecutorService 中的那些。在 Eclipse 中调试时,您可以更改断点以停止所有线程,而不仅仅是主线程。

      当不调试任务的提交和立即取消时,您会在任务运行一次之前取消任务。尝试在这些行之间添加睡眠延迟:

      final Future<String> future =  pool.submit(new TaskChecksForInterruptedBit());
      Thread.sleep(1000);
      final boolean wasJustCancelled = future.cancel(true);
      

      【讨论】:

      • 为什么主线程在发布模式下看不到修改标志(由衍生线程修改)?
      • 让我澄清一下:我把它放在测试方法中的 'interruptedBitSet = false' 上,而不是 Callable 的 call() 方法。
      • @Chris-Morris 对不起,我先看错了代码,我已经用另一个建议编辑了我的答案
      【解决方案5】:

      您必须确保您的任务真正开始运行。它甚至可能在它有机会之前被取消。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-06-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-01
        • 2017-10-12
        • 1970-01-01
        相关资源
        最近更新 更多