2010-10-28 19 views
6

Me encuentro con un problema relacionado con el uso de JUnit en entornos de subprocesos múltiples. El siguiente código debería fallar, pero en realidad pasa en eclipse.Problema extraño al utilizar JUnit en entornos de subprocesos múltiples

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); 
     } 
    } 
} 

Y here'a otra pieza de código, aquí utilizo Future.get() para esperar a tope de la rosca, en este caso, se producirá un error.

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(); 
    } 
} 

busqué en Google y encontró que JUnit no puede manejar la unidad de pruebas de varias hebras, pero lo que es la diferencia entre estas dos piezas de código? Gracias

Respuesta

6

JUnit no puede ver las excepciones que ocurren en los subprocesos que no sean el subproceso en el que se ejecutan las pruebas. En el primer caso, a través de una excepción se produce al llamar al fail, se produce en un subproceso independiente ejecutado por el executor. Por lo tanto, no es visible para JUnit y la prueba pasa.

En el segundo caso, la misma excepción ocurre en el hilo separado dirigido por el executor pero la excepción es "informó" de manera efectiva a la rosca de prueba cuando se llama a future.get. Esto es porque future.get arroja un ExecutionException si el cálculo del futuro falló debido a alguna excepción. JUnit puede ver esta excepción y, por lo tanto, la prueba falla.

+0

todo, hay una reemplazo de Junit en este caso? – zjffdu

0

Eche un vistazo a http://www.youtube.com/watch?v=wDN_EYUvUq0 (a partir de las 17:09), explica los problemas que puede encontrar con JUnit y los hilos.

Creo que, en su caso, get() arroja un ExecutionException y es por eso que la segunda prueba falla. En el primer caso de prueba, jUnit no ve la excepción.

0

También existe el hecho interesante de que Eclipse e IDEA pueden engendrar una VM en sus corredores de prueba junit y terminan llamando a system.exit() en ella. Esto significa que si no espera adecuadamente en la prueba (como en el caso cuando duerme arriba y espera que la tarea se haya completado), puede salir inesperadamente. ¡Interesante, pero no exactamente lo que estabas preguntando!

ver este link para más detalles ...

1

Como @ abhin4v ha señalado, la excepción en el nuevo hilo es tragada. Podría intentar proporcionar su propio fail -metodo que sincroniza con el subproceso de nivel superior de forma muy parecida a su ejemplo con get().

Pero no es necesario utilizar futuros, simplemente escriba en una variable compartida que indique la falla y use newThreadId.join(). Aparte de eso, no estoy al tanto de ninguna otra forma de resolver esto en un solo JUnit.

2

@zjffdu Como @ShiDoiSi señaló, Thread.join() funciona bien si tiene un solo hilo de trabajo que desea afirmar o no.

Si tiene varios subprocesos de trabajo, o si quieres un poco más de comodidad, hay una extensión de JUnit para realizar afirmaciones multi-hilo: 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(); 
    } 
} 

Buena suerte

Cuestiones relacionadas