2013-03-02 21 views
6

Perché il test dell'unità ha esito positivo in modalità di debug ma non riesce durante l'esecuzione normale?Il test di unità ha esito positivo in modalità di debug ma non riesce quando lo si esegue normalmente

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

Suggerimento, provare a rendere il 'interruptedBitSet'' volatile' – yohlulz

+0

Questo non ha funzionato. –

+0

Dove si trova il punto di interruzione durante il debug? – Alb

risposta

1

Devi assicurarti che l'attività sia effettivamente iniziata. Potrebbe essere cancellato prima ancora che abbia una possibilità.

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

Il motivo è quasi certamente che il vostro punto di interruzione nel debugger è arrestare il thread principale, ma non uno qualsiasi dei thread in background - quelli della ExecutorService. Quando esegui il debug in eclissi puoi modificare il punto di interruzione in modo da interrompere tutti i thread anziché solo quello principale.

Quando non eseguire il debug dell'invio dell'attività e l'annullamento immediato sono così veloci che si sta annullando l'attività prima ancora che venga eseguita una sola volta. Prova ad aggiungere un ritardo di sospensione tra queste righe:

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

Perché il thread principale non vede il flag modificato (modificato dal thread generato) nella modalità di rilascio? –

+0

Mi permetta di chiarire: l'ho messo su 'interruptedBitSet = false' nel metodo di test, non il metodo call() di Callable. –

+0

@ Chris-Morris scusa, ho letto male il codice prima, ho modificato la mia risposta con un altro suggerimento – Alb

1

So che questo è vecchio ma ho avuto lo stesso problema. Il mio problema era che avevo un IEnumerable che stavo enumerando e controllando l'output.

Durante il test dell'unità, IEnumerable restituiva un ordine diverso durante il debug. Questa è la natura di IEnumerable e la semplice aggiunta di una clausola OrderBy ha risolto il problema.

Spero che questo aiuti qualcuno là fuori in quanto può essere un problema frustrante da trovare.

0

si dovrebbe verificare se tutti i fili muore prima di terminare il thread principale

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

stavo avendo un problema simile durante l'esecuzione di un compito a casa da un corso online. Il programma di grader del corso che ho aggiunto al percorso di build ha utilizzato JUnit4, la mia versione di Eclipse ha aggiunto JUnit5 a qualsiasi nuovo caso di test. Ho creato un nuovo progetto Java e aggiunto JUnit5 al bagno di build per i miei casi di test senza il selezionatore e lo ha risolto per me. Spero che questo ti aiuti.