2011-04-15 23 views
9

Tengo un montón de pruebas que se organizan en conjuntos de pruebas JUnit. Estas pruebas utilizan mucho selenio para probar una aplicación web. Entonces, naturalmente para el selenio, el tiempo de ejecución de estas pruebas es bastante largo. Dado que las clases de prueba en las suites no pueden ejecutarse en paralelo debido a algunas superposiciones en la base de datos de prueba, me gustaría ejecutar las suites en paralelo.Ejecutando JUnit Test en paralelo en Suite Level?

El JUnit ParallelComputer solo puede ejecutar pruebas en clase o nivel de método en paralelo, ¿hay alguna forma estándar para que JUnit lo haga con suites?

Si acabo de pasar las clases de suite al corrector junit y configurar la computadora para que se paralelice en el nivel de clase, elige las clases de prueba en sí, no las suites.

br Frank

Respuesta

1

Desde Suite se utiliza para anotar una clase, por lo que ejecutar la clase Suite-anotada en JUnitCore.runClasses(ParallelComputer.classes(), cls) manera. cls son clases anotadas en Suite.

@RunWith(Suite.class) 
@Suite.SuiteClasses({ 
Test1.class, 
Test2.class}) 
public class Suite1 { 
} 

@RunWith(Suite.class) 
@Suite.SuiteClasses({ 
Test3.class, 
Test4.class}) 
public class Suite2 { 
} 
... 
JUnitCore.runClasses(ParallelComputer.classes(), new Class[]{Suite1.class, Suite2.class}) 
+0

Hola, gracias por la respuesta quik. Lamentablemente, esto no ejecuta la prueba de la manera que pretendía. Al igual que escribí al final de mi pregunta, esto ejecuta las clases de prueba dentro del paquete paralelo, no las suites en sí. – Frank

+0

Su ejemplo se ejecuta de la siguiente manera: Test1 y Test2 se ejecutan en paralelo, exactamente el comportamiento que debo evitar. – Frank

+0

¡Bienvenido! Si mi código no puede ayudarlo, puede escribir múltiples hilos para ejecutar sus Suites (si no hay una solución mejor). –

8

Aquí hay un código que funcionó para mí. Yo no escribí esto. Si usa @RunWith(ConcurrentSuite.class) en lugar de @RunWith(Suite.class) debería funcionar. Hay una anotación que también se necesita que se encuentra a continuación.

package utilities.runners; 

import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; 
import org.junit.runner.Runner; 
import org.junit.runners.Suite; 
import org.junit.runners.model.InitializationError; 
import org.junit.runners.model.RunnerBuilder; 
import org.junit.runners.model.RunnerScheduler; 

import utilities.annotations.Concurrent; 

import java.util.Arrays; 
import java.util.LinkedList; 
import java.util.List; 
import java.util.Queue; 
import java.util.concurrent.CompletionService; 
import java.util.concurrent.ExecutorCompletionService; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import java.util.concurrent.ThreadFactory; 
import java.util.concurrent.atomic.AtomicInteger; 

/** 
* @author Mathieu Carbou ([email protected]) 
*/ 
public final class ConcurrentSuite extends Suite { 
    public ConcurrentSuite(final Class<?> klass) throws InitializationError { 
     super(klass, new AllDefaultPossibilitiesBuilder(true) { 
      @Override 
      public Runner runnerForClass(Class<?> testClass) throws Throwable { 
       List<RunnerBuilder> builders = Arrays.asList(
         new RunnerBuilder() { 
          @Override 
          public Runner runnerForClass(Class<?> testClass) throws Throwable { 
           Concurrent annotation = testClass.getAnnotation(Concurrent.class); 
           if (annotation != null) 
            return new ConcurrentJunitRunner(testClass); 
           return null; 
          } 
         }, 
         ignoredBuilder(), 
         annotatedBuilder(), 
         suiteMethodBuilder(), 
         junit3Builder(), 
         junit4Builder()); 
       for (RunnerBuilder each : builders) { 
        Runner runner = each.safeRunnerForClass(testClass); 
        if (runner != null) 
         return runner; 
       } 
       return null; 
      } 
     }); 
     setScheduler(new RunnerScheduler() { 
      ExecutorService executorService = Executors.newFixedThreadPool(
        klass.isAnnotationPresent(Concurrent.class) ? 
          klass.getAnnotation(Concurrent.class).threads() : 
          (int) (Runtime.getRuntime().availableProcessors() * 1.5), 
        new NamedThreadFactory(klass.getSimpleName())); 
      CompletionService<Void> completionService = new ExecutorCompletionService<Void>(executorService); 
      Queue<Future<Void>> tasks = new LinkedList<Future<Void>>(); 

      @Override 
      public void schedule(Runnable childStatement) { 
       tasks.offer(completionService.submit(childStatement, null)); 
      } 

      @Override 
      public void finished() { 
       try { 
        while (!tasks.isEmpty()) 
         tasks.remove(completionService.take()); 
       } catch (InterruptedException e) { 
        Thread.currentThread().interrupt(); 
       } finally { 
        while (!tasks.isEmpty()) 
         tasks.poll().cancel(true); 
        executorService.shutdownNow(); 
       } 
      } 
     }); 
    } 

    static final class NamedThreadFactory implements ThreadFactory { 
     static final AtomicInteger poolNumber = new AtomicInteger(1); 
     final AtomicInteger threadNumber = new AtomicInteger(1); 
     final ThreadGroup group; 

     NamedThreadFactory(String poolName) { 
      group = new ThreadGroup(poolName + "-" + poolNumber.getAndIncrement()); 
     } 

     @Override 
     public Thread newThread(Runnable r) { 
      return new Thread(group, r, group.getName() + "-thread-" + threadNumber.getAndIncrement(), 0); 
     } 
    } 

} 

Y la anotación es la siguiente.

package utilities.annotations; 

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 

/** 
* @author Mathieu Carbou ([email protected]) 
*/ 
@Retention(RetentionPolicy.RUNTIME) 
@Target({ ElementType.TYPE }) 
public @interface Concurrent { 
    int threads() default 5; 
} 
+1

Parece que hay una copia de este código disponible en esta URL http://mycila.googlecode.com/svn/sandbox/src/main/java/com/mycila/sandbox/junit/runner/ –

+0

Sí, debería haber incluido el enlace. Gracias. –

+0

Esto funcionó después de agregar un constructor adicional: \t public ConcurrentSuite (clase klass, constructor RunnerBuilder) arroja InitializationError { \t \t this (klass); \t} –

Cuestiones relacionadas