2010-10-28 15 views
6

Ho riscontrato un problema estenuante quando si utilizza JUnit in ambiente multi-thread. Il seguente codice dovrebbe fallire, ma in realtà passa in eclissi.Problema strano che utilizza JUnit nell'ambiente multi-thread

public class ExampleTest extends TestCase { 

    private ExecutorService executor = Executors.newFixedThreadPool(10); 

    private volatile boolean isDone = false; 

    public void test() throws InterruptedException, ExecutionException { 
     executor.submit(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        fail(); 
       } finally { 
        isDone = true; 
       } 
      } 
     }); 

     while (!isDone) { 
      Thread.sleep(1000); 
     } 
    } 
} 

E here'a un altro pezzo di codice, qui io uso Future.get() per attendere per l'arresto del filo, in questo caso fallirà.

public class ExampleTest extends TestCase { 

    private ExecutorService executor = Executors.newFixedThreadPool(10); 

    private volatile boolean isDone = false; 

    public void test() throws InterruptedException, ExecutionException { 
     Future future=executor.submit(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        fail(); 
       } finally { 
        isDone = true; 
       } 
      } 
     }); 

     future.get(); 
    } 
} 

ho cercato con Google e ha scoperto che JUnit non è in grado di gestire più thread unit test, ma ciò che è la differenza tra questi due pezzi di codice? Grazie

risposta

6

JUnit non può vedere le eccezioni che si verificano in thread diversi dal thread in cui sono in esecuzione i test. Nel primo caso, tramite un'eccezione si verifica chiamando fail, si verifica in un thread separato eseguito da executor. Quindi non è visibile a JUnit e ai passaggi di test.

Nel secondo caso, la stessa eccezione si verifica nel thread separato eseguito da executor ma l'eccezione viene effettivamente "riportata indietro" al thread di test quando si chiama future.get. Questo perché future.get genera un ExecutionException se il calcolo del futuro non è riuscito a causa di alcuna eccezione. JUnit è in grado di vedere questa eccezione e quindi il test fallisce.

+0

Quindi v'è alcuna sostituzione per Junit in questo caso? – zjffdu

0

Dai uno sguardo allo http://www.youtube.com/watch?v=wDN_EYUvUq0 (a partire dalle 17:09), spiega i problemi che puoi ottenere con JUnit e i thread.

Penso che nel tuo caso, get() lanci uno ExecutionException ed è per questo che il secondo test fallisce. Nel primo testcase, jUnit non vede l'eccezione.

0

C'è anche il fatto interessante che Eclipse e IDEA possono generare una VM nei loro runner di test di junit e terminare chiamando system.exit() su di essa. Ciò significa che se non si attende correttamente il test (come nel caso in cui si dorme sopra e si spera che l'attività sia completata), può uscire in modo imprevisto. Interessante, ma non esattamente quello che stavi chiedendo!

vedono questo link per i dettagli ...

1

Come @ abhin4v ha fatto notare, l'eccezione nel nuovo thread viene inghiottito. Potresti provare a fornire il tuo metodo fail che sincronizza con il thread di primo livello molto simile al tuo esempio con get().

Ma non è necessario utilizzare Futures, basta scrivere su una variabile condivisa che indica l'errore e utilizzare newThreadId.join(). A parte questo, non sono a conoscenza di nessun altro modo di risolvere questo in puro JUnit.

2

@zjffdu Come sottolineato da @ShiDoiSi, Thread.join() funziona correttamente se si dispone di un singolo thread di lavoro da cui si desidera affermare o fallire.

Se si dispone di più thread di lavoro, o se si vuole un po 'più di comodità, v'è un'estensione JUnit per l'esecuzione di asserzioni multi-threaded: ConcurrentUnit:

public class ExampleTest extends ConcurrentTestCase { 
    private ExecutorService executor = Executors.newFixedThreadPool(10); 

    public void test() throws Throwable { 
     executor.submit(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        threadFail("Failure message"); 
       } finally { 
        resume(); 
       } 
      } 
     }); 

     threadWait(); 
    } 
} 

Buona fortuna

Problemi correlati