2012-01-27 15 views
6

Estoy usando JUnit 4.10 para ejecutar suites de prueba, y he implementado una regla de "prueba fallida de reintentar" siguiendo las impresionantes notas de Matthew Farwell en la publicación How to Re-run failed JUnit tests immediately?. He creado una clase "RetryTestRule" con el siguiente código:Cómo aplicar un JUnit @Rule para todos los casos de prueba en un conjunto

public class RetryTestRule implements TestRule { 

    private final int retryCount; 

    public RetryTestRule(int retryCount) { 
    this.retryCount = retryCount; 
    } 

    @Override 
    public Statement apply(Statement base, Description description) { 
    return statement(base, description); 
    } 

    private Statement statement(final Statement base, final Description description) { 
    return new Statement() { 
     @Override 
     public void evaluate() throws Throwable { 
     Throwable caughtThrowable = null; 

     // retry logic 
     for (int i = 0; i < retryCount; i++) { 
      try { 
      base.evaluate(); 
      return; 
      } catch (Throwable t) { 
      caughtThrowable = t; 
      System.err.println(description.getDisplayName() + ": run " + (i + 1) + "  failed"); 
      } 
     } 
     System.err.println(description.getDisplayName() + ": Giving up after " + retryCount 
      + " failures"); 
     throw caughtThrowable; 
     } 
    }; 
    } 
} 

Al utilizar esto como una regla dentro de un caso de prueba que funciona perfectamente, pero no parece óptimo utilizar la notación @Rule en todos los casos de prueba de una suite en vez de una única anotación en la definición suite, por lo que después de revisar un poco probé la nueva notación @ClassRule en mi clase suite:

@RunWith(Suite.class) 
@SuiteClasses({ 
    UserRegistrationTest.class, 
    WebLoginTest.class 
}) 
public class UserSuite {  
    @ClassRule 
    public static RetryTestRule retry = new RetryTestRule(2); 
} 

el problema es que esto no funciona como se esperaba: Error no están siendo juzgados de pruebas . ¿Alguien ha intentado esto y conoce una solución? ¡La ayuda es muy apreciada!

+0

Puede ser un duplicado: http://stackoverflow.com/questions/7639353/how-to-define-junit-method-rule-in-a-suite – pholser

+0

No le preocupa en absoluto que su unidad las pruebas fallan al azar? – Tobb

Respuesta

6

@ClassRule s se ejecutan una vez por clase, no una vez por método. Para ejecutar algo una vez por método, debe usar @Rule como lo hace, o seguir la respuesta para How to define JUnit method rule in a suite?.

volver a utilizar la regla existente, se puede añadir la regla a la lista de reglas para funcionar, utilizando la clase RunRules de la siguiente manera:

public class MyRunner extends BlockJUnit4ClassRunner { 
    public MyRunner(Class<?> klass) throws InitializationError { 
     super(klass); 
    } 

    @Override 
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) { 
     Description description= describeChild(method); 
     if (method.getAnnotation(Ignore.class) != null) { 
      notifier.fireTestIgnored(description); 
     } else { 
      RunRules runRules = new RunRules(methodBlock(method), Arrays.asList(new TestRule[]{new RetryTestRule(3)}), description); 
      runLeaf(runRules, description, notifier); 
     } 
    } 
} 

Esto es usando el ejemplo de la respuesta anterior. También podría combinar las dos respuestas para un control más detallado, creando una RetryTestRule si hubiera una anotación en su prueba, por ejemplo.

+0

Muchas gracias por su respuesta rápida, Matthew. Combiné ambas respuestas como sugirió y creé fácilmente un corredor y suite personalizados. Luego agregué @RunWith (MySuite.class) a mi suite y ¡voilà! Reintentar prueba automática en caso de falla para todo el paquete :) – jbaxenom

+0

Me falta algo o este enfoque (* combinación de ambas respuestas *) hace que las pruebas se ejecuten antes de la ejecución de la '@ClassRule ... ExternalResource .. .. antes del método' – Daniel

Cuestiones relacionadas