2010-05-14 23 views
16

Cuando pruebo la ejecución de un método que crea un subproceso secundario, la prueba JUnit finaliza antes del subproceso secundario y lo mata.JUnit termina subprocesos secundarios

¿Cómo obligo a JUnit a esperar a que el subproceso secundario complete su ejecución?

Gracias

Respuesta

7

Después de leer la pregunta y algunos comentarios, parece que lo que necesita es una técnica para probar unidades de operaciones asincrónicas. doSomething() regresa inmediatamente, pero desea que el código de prueba espere su finalización y luego realice algunas validaciones.

El problema es que la prueba no tiene conocimiento de los hilos generados por la llamada, por lo que aparentemente no tiene forma de esperarlos. Uno puede pensar en muchas formas sofisticadas (y probablemente defectuosas) para resolver esto, pero en mi opinión hay un problema de diseño aquí. Una prueba unitaria debe simular un cliente de alguna API, y no debe asumir nada sobre la implementación; Solo debe probar la funcionalidad, como se refleja en la API y su documentación. Por lo tanto, evitaría tratar de detectar y rastrear los hilos creados por la llamada asynch. En cambio, mejoraría la API de la clase probada, si es necesario. La clase a la que pertenece la llamada de asincron debe proporcionar algún mecanismo para detectar la terminación. No puedo pensar en 3 maneras, pero probablemente hay más:

1) Permitir el registro de un oyente que consigue notificado una vez que se haya completado la operación

2) Proporcionar una versión sincrónica de la operación. La implementación puede llamar a la versión de bloqueo y luego bloquear hasta su finalización. Si la clase no debe exponer dicho método, su visibilidad se puede reducir al paquete protegido, para que la prueba pueda acceder a él.

3) Uso del patrón wait-notify, en algún objeto visible.

Si la clase no proporciona tal mecanismo, entonces no es realmente comprobable y, lo que es peor, probablemente tampoco sea muy reutilizable.

2

Trate de usar thread.join() en el hilo creado. Esto esperará a que ese hilo muera.

Editar: para evitar esto, intente con Thread.getThreadGroup().setDaemon(true); en la prueba, o quizás en el método setUp(). No he probado esto sin embargo.

Un grupo de hilos daemon se destruye automáticamente cuando se detiene el último hilo o se destruye el último grupo de hilos.

Me pregunto si JUnit llama al System.exit() o algo tan pronto como finaliza la prueba, sin embargo.

+0

En realidad, yo evitaría esta solución, en su lugar estaba buscando una mejor manera de ejecutar este tipo de pruebas y forzar al hilo principal a esperar hasta el final de sus hijos. – Mark

+0

@Marco: ¿pueden por favor dar más detalles? ¿Qué pasa con la solución de Chris? –

+0

Estoy probando un método doSomething() que inicia internamente algunos subprocesos que actualizan algunas tablas db. Lo que me gustaría hacer es ejecutar este método dentro de mi prueba JUnit y luego verificar si todas las ediciones en la base de datos se han guardado con éxito. Es importante que el método doSomething() no se una a los subprocesos cuando se crean, por lo que no puedo adoptar la solución join(). – Mark

0

Quizás agrupar sus hilos con una ExecutorService, a continuación, utilizar apagado y awaitTermination método?

La condición es usar Runnable o Future, no Threads.

+1

JUnit no espera a que finalice ExecutorService. – koppor

1

La técnica básica que @Eyal delineó es para lo que se destina ConcurrentUnit.El uso general es:

  1. freza algunos hilos
  2. tener la espera del hilo principal o dormir
  3. Realizar afirmaciones desde el interior de los subprocesos de trabajo (que a través de ConcurrentUnit, se informó al hilo principal)
  4. Reanudar el hilo principal de uno de los hilos de trabajo una vez que se completen todas las afirmaciones

Consulte la página ConcurrentUnit para obtener más información.

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

Puede intentar bloquear el subproceso JUnit y esperar a que se complete el subproceso. El Thread.sleep() es necesario para que su hilo no acapare la CPU. En este ejemplo s sería su hilo, necesitará tener un método isRunning() para que pueda verificar si el hilo todavía se está ejecutando cada SLEEP_TIME milisegundos. Sé que esta no es la mejor solución, pero si solo tienes 2 hilos y no quieres que JUnit elimine tu hilo, esto funciona. El ciclo while causa que este subproceso JUnit permanezca activo y espere a que termine el otro subproceso.