2013-03-02 10 views
6

Dlaczego mój test jednostki kończy się sukcesem w trybie debugowania, ale kończy się niepowodzeniem podczas normalnego działania?Test jednostki powiodł się w trybie debugowania, ale kończy się niepowodzeniem podczas normalnego działania.

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

Sugestia, spróbuj wprowadzić 'interruptedBitSet'' volatile' – yohlulz

+0

To nie zadziałało. –

+0

Gdzie jest twój punkt przerwania podczas debugowania? – Alb

Odpowiedz

1

Musisz się upewnić, że zadanie faktycznie zaczęło działać. Może zostać anulowana, zanim jeszcze będzie miała szansę.

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

Powodem jest to prawie na pewno, że punkt przerwania w debugerze jest powstrzymanie główny wątek, ale nie każdy z wątków tła - te w ExecutorService. Podczas debugowania w środowisku Eclipse można zmienić punkt przerwania, aby zatrzymać wszystkie wątki zamiast tylko głównego.

Gdy brak debugowania przedłożenie zadania i natychmiastowe anulowanie jest tak szybkie, że anulujesz zadanie, zanim zostanie ono uruchomione tylko raz. Spróbuj dodać opóźnienie uśpienia między tymi liniami:

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

Dlaczego główny wątek nie wyświetla zmodyfikowanej flagi (zmodyfikowanej przez zarodkowany wątek) w trybie zwolnienia? –

+0

Pozwól mi wyjaśnić: umieściłem go w "interruptedBitSet = false" w metodzie testowej, a nie w metodzie Call() wywołania. –

+0

@ Chris-Morris Przepraszam, źle odczytałem kod, edytowałem swoją odpowiedź z inną sugestią – Alb

1

Wiem, że to jest stare, ale miałem ten sam problem. Mój problem polegał na tym, że miałem IEnumerable, że wyliczyłem i sprawdziłem wynik.

Po uruchomieniu testu jednostki, IEnumerable zwrócił inną kolejność podczas debugowania. Taka jest natura IEnumerable i po prostu dodanie klauzuli OrderBoy rozwiązało mój problem.

Mam nadzieję, że to pomoże komuś tam dotrzeć, ponieważ może to być frustrujący problem.

0

Należy sprawdzić, czy wszystkie gwinty umrze przed zakończeniem głównego wątku

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

miałem podobny problem podczas uruchamiania zadanie domowe z kursu online. Program gradator z kursu, który dodałem do ścieżki kompilacji użyłem JUnit4, moja wersja Eclipse dodała JUnit5 do nowych przypadków testowych. Stworzyłem nowy projekt Java i dodałem JUnit5 do wanny do budowy dla moich testowych przypadków bez równiarki i naprawiłem to dla mnie. Mam nadzieję że to pomoże.

Powiązane problemy