2010-05-14 11 views
16

Quando eseguo il test sull'esecuzione di un metodo che crea un thread figlio, il test JUnit termina prima del thread secondario e lo uccide.JUnit termina i thread figlio

Come faccio a forzare JUnit per aspettare che il thread secondario completi l'esecuzione?

Grazie

risposta

7

Dopo aver letto la domanda e alcuni commenti, sembra che quello che ti serve è una tecnica per unità di test operazioni asincrone. doSomething() restituisce immediatamente, ma si desidera che il codice di test attenda il suo completamento, quindi esegue alcune convalide.

Il problema è che il test non è a conoscenza dei thread generati dalla chiamata, quindi apparentemente non ha modo di aspettarli. Si può pensare a molti modi sofisticati (e probabilmente imperfetti) per risolvere questo problema, ma secondo me c'è un problema di progettazione qui. Un test unitario dovrebbe simulare un client di alcune API e non dovrebbe assumere nulla sull'implementazione; Dovrebbe solo testare la funzionalità, come riflesso dall'API e dalla sua documentazione. Pertanto, eviterei di provare a rilevare e tenere traccia dei thread creati dalla chiamata asynch. Invece, migliorerei l'API della classe testata, se necessario. La classe a cui appartiene la chiamata asynch dovrebbe fornire un meccanismo per rilevare la terminazione. Mi viene in mente 3 modi, ma ci sono probabilmente più:

1) Consentire la registrazione di un ascoltatore che viene comunicata una volta che l'operazione è completata

2) Fornire una versione sincrona dell'operazione. L'implementazione può chiamare la versione asynch e quindi bloccare fino al completamento. Se la classe non deve esporre un tale metodo, la sua visibilità può essere ridotta a pacchetto protetto, in modo che il test possa accedervi.

3) Utilizzando lo schema di attesa-notifica, su qualche oggetto visibile.

Se la classe non fornisce tale meccanismo, non è realmente verificabile e, peggio, probabilmente non è molto riutilizzabile.

2

Prova utilizzando thread.join() sul thread creato. Questo attenderà che quel thread muoia.

Modifica: per evitare questo, provare Thread.getThreadGroup().setDaemon(true); nel test, o forse nel metodo setUp(). Non ho provato questo però.

Un gruppo di thread daemon viene automaticamente distrutto quando viene interrotto l'ultimo thread o viene distrutto l'ultimo gruppo di thread.

Mi chiedo se JUnit chiami System.exit() o qualcosa non appena termina il test, tuttavia.

+0

In realtà vorrei evitare questa soluzione, invece cercavo un modo migliore per eseguire questo tipo di test e forzare il thread principale ad attendere la fine dei suoi figli. – Mark

+0

@Marco: puoi per favore elaborare? cosa c'è di sbagliato nella soluzione di Chris? –

+0

Sto testando un metodo doSomething() che avvia internamente alcuni thread che aggiornano alcune tabelle db. Quello che mi piacerebbe fare è eseguire questo metodo all'interno del mio test JUnit e quindi verificare se tutte le modifiche sul database sono state salvate correttamente. È importante che il metodo doSomething() non unisca i thread quando vengono creati e quindi non posso adottare la soluzione join(). – Mark

0

Forse raggruppare i fili con un ExecutorService, quindi utilizzare arresto e awaitTermination metodo?

La condizione è utilizzare Runnable o Future, non Threads stessi.

+1

JUnit non attende che ExecutorService termini. – koppor

1

La tecnica di base che @Eyal ha delineato è quella per cui è previsto ConcurrentUnit.L'uso generale è:

  1. Spawn alcuni fili
  2. hanno il principale attesa filo o dormire
  3. Eseguire asserzioni dall'interno i thread di lavoro (che tramite ConcurrentUnit, sono riportati indietro al thread principale)
  4. Riprendere il thread principale da uno dei thread di lavoro una volta che tutte le asserzioni sono complete

Vedere la pagina ConcurrentUnit per ulteriori informazioni.

0
 while (s.isRunning()) { 
      try { 
       Thread.sleep(SLEEP_TIME); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 

Si potrebbe provare a bloccare il thread JUnit e attendere il completamento del thread. È necessario il Thread.sleep() in modo che il thread non esegua il controllo della CPU. In questo esempio, la tua discussione dovrebbe essere il metodo isRunning() in modo da poter verificare se il thread è ancora in esecuzione ogni millesimo di secondo SLEEP_TIME. So che questa non è la soluzione migliore, ma se hai solo 2 thread e non vuoi che JUnit uccida il tuo thread, questo funziona. Il ciclo while fa sì che questo thread JUnit rimanga attivo e aspetti che l'altro thread finisca.

Problemi correlati