2013-05-17 21 views
13

Sto provando a scrivere un test unitario che richiede thread multipli. Tuttavia, sembra che i thread si fermino solo in parte attraverso l'esecuzione. Si consideri il seguente codice:Thread che si comporta stranamente in JUnit

public class Test { 
    @org.junit.Test 
    public void TestThreads() { 
     new Thread(new Runnable() { 
      public void run() { 
       for (int i = 1; i < 1000; i++) System.out.println(i); 
      } 
     }).start(); 
    } 
} 

Se ho eseguito questo test di unità, sarà generalmente interrompere la visualizzazione di uscita da qualche parte tra 140-180. Se converto questo codice in una classe regolare ed eseguirlo, funziona correttamente. Qualcuno ha idea di cosa mi manchi qui?

Grazie, - Andrew.

risposta

0

Probabilmente il thread principale che sta eseguendo il test sta finendo. Se puoi evitarlo, non creare una nuova discussione nei tuoi test. Creerei una nuova classe che implementa il runnable e poi testò quella classe che la mia chiamata semplicemente eseguiva su quell'oggetto. Non dovresti avere bisogno di testare la programmazione dei thread come parte dei tuoi test. Spero che il team di sviluppo della lingua Java abbia quello coperto :)

6

Nella funzione TestThread, JUnit non ha modo di dire che hai generato un nuovo thread. Recluta qualsiasi oggetto creato nella funzione non appena termina la funzione (viene raggiunta l'ultima riga) e non conosce il thread.

Per questo motivo, viene visualizzato Output dal thread fino a quando non viene ucciso. Se si desidera attendere il completamento del thread, è possibile utilizzare Thread.join (subito dopo aver chiamato Thread.start()) per farlo attendere il risultato o utilizzare wait-notify su alcuni oggetti.

Inoltre, pensa che questa domanda: JUnit terminates child threads

+0

Dire che gli oggetti "cancella" JUnit è un po 'fuorviante, poiché in Java non esiste un modo per eliminare esplicitamente un oggetto. –

+0

@Martin a destra. ma JVM può reclamare (GC) quando l'oggetto non è più necessario. Una volta terminati i test, JUnit elimina Thread e fondamentalmente l'intera JVM. – goblinjuice

+0

@goblinjuice che non significa che JUnit uccida un'istanza dell'oggetto. Poiché la JVM termina, tutti i singoli bit di memoria utilizzati verranno liberati. –

22

È possibile utilizzare Thread.join() per evitare il test di finire prima che il nuovo thread ha completato il suo compito:

@org.junit.Test 
public void TestThreads() throws InterruptedException { 
    Thread t = new Thread(new Runnable() { 
     public void run() { 
      for (int i = 1; i < 1000; i++) System.out.println(i); 
     } 
    }); 
    t.start(); 
    t.join(); 
} 

Normalmente, la JVM terminerà quando l'ultimo il thread non daemon termina. Ci si potrebbe aspettare che semplicemente chiamando t.setDaemon(false) sul thread si impedisca alla JVM di uscire prima che l'attività sia terminata. Tuttavia, junit sarà call System.exit() al termine del thread principale.

Come osserva Gus nei commenti: "è necessario join() perché start() non blocca".

Ha ragione che è possibile chiamare anche run() in questo esempio minimo. Tuttavia, presumo che stai iniziando un thread perché vuoi che venga eseguito contemporaneamente ad un altro thread. Chiamare run() su una discussione è contrassegnato come un possibile errore da FindBugs - se hai appena intenzione di chiamare run(), probabilmente vorrai implementare Runnable invece di usare Thread.

+0

Sigh - mi ha battuto per il punch fair and square. –

+1

Vale la pena menzionare nella soluzione che è necessario Join() perché Start() non blocca. IIRC, potresti anche usare Run() se non hai intenzione di fare nulla in modo simultaneo. – Gus

+0

@Gus che usa 'run' su un'istanza' Thread' è una cattiva idea. Perché?Perché l'uso di 'run' non lo rende un thread, ma solo un oggetto semplice. –

Problemi correlati