2012-08-22 9 views
15

Tengo un banco de pruebas donde estoy cerrando la sesión del sistema en @After y cerrando el navegador en @AfterClass. Intento usar @Rule para tomar una captura de pantalla de prueba fallida usando Selenium para cada método de prueba. Comprobé manualmente que @Rule solo se ejecuta antes de cada @Before, pero quiero configurarlo después de @Test y antes de @After. No pude encontrar una solución simple. Cualquier ayuda será apreciada.Aplicar '@Rule' después de cada '@Test' y antes de cada '@ After' en JUnit

public class MorgatgeCalculatorTest { 

@Before 
public void before(){ 
    System.out.println("I am before"); 
} 
@BeforeClass 
public static void beforeclass(){ 
    System.out.println("I am beforeclass"); 
} 
@Test 
    public void test(){ 
     System.out.println("I am Test"); 
    } 
@Test 
public void test2(){ 
    System.out.println("I am Test2"); 
} 
@After 
    public void after(){ 
     System.out.println("I am after"); 
    } 
@AfterClass 
     public static void afterclass(){ 
      System.out.println("I am afterclass"); 

} 
@Rule 
ExpensiveExternalResource ExpensiveExternalResource = new ExpensiveExternalResource(); 

static class ExpensiveExternalResource implements MethodRule { 
    public ExpensiveExternalResource(){ 
     System.out.println("I am rule"); 
    } 

    @Override 
    public Statement apply(Statement arg0, FrameworkMethod arg1, Object arg2) { 
     // TODO Auto-generated method stub 
     return null; 
    }  
}    

La salida que estoy recibiendo es

I am beforeclass 
I am rule 
I am before 
I am Test 
I am after 
I am rule 
I am before 
I am Test2 
I am after 
I am afterclass 
+0

He mencionado que solo quiero tomar capturas de pantalla solo cuando falla una prueba. No para todas las pruebas: D –

+0

Gracioso. Solo estaba interesado en el pedido, así que en realidad tu pregunta era mi respuesta :) –

+0

@ GáborLipták :) ¡Estoy contento! –

Respuesta

19

Debido a la forma en que se establecen las reglas, no puede tener una regla que aparezca después de @antes o antes de @después. Puedes pensar en reglas como las conchas que pones en el método de prueba. El primer shell para continuar es @ before/@ after. A partir de entonces, se aplican las reglas @.

Una forma rápida de hacer lo que quiere hacer es evitar @Después de todo. Se puede crear una regla para que tome una captura de pantalla si falla un método y luego ejecutar el suyo después del código. No es tan bonito como @ After, pero funciona. (También implementé TestRule porque MethodRule se ha depreciado).

public class MortgageCalculatorTest { 
    @Before 
    public void before(){ 
     System.out.println("I am before"); 
    } 

    @BeforeClass 
    public static void beforeclass(){ 
     System.out.println("I am beforeclass"); 
    } 

    @Test 
    public void test(){ 
     System.out.println("I am a Test"); 
    } 

    @Test 
    public void test2(){ 
     System.out.println("I am a Failed Test"); 
     fail(); 
    } 

    @AfterClass 
      public static void afterclass(){ 
       System.out.println("I am afterclass"); 

    } 

    @Rule 
    public ExpensiveExternalResource ExpensiveExternalResource = new ExpensiveExternalResource(); 

    public static class ExpensiveExternalResource implements TestRule { 


     // public ExpensiveExternalResource(){} 


     public class ExpansiveExternalResourceStatement extends Statement{ 

      private Statement baseStatement; 

      public ExpansiveExternalResourceStatement(Statement b){ 
       baseStatement = b; 
      } 

      @Override 
      public void evaluate() throws Throwable { 
       try{ 
        baseStatement.evaluate(); 
       }catch(Error e){ 
        System.out.println("I take a Screenshot"); 
        throw e; 
       }finally{ 
        after(); 
       } 
      } 

      //Put your after code in this method! 
      public void after(){ 
       System.out.println("I am after"); 
      } 
     } 

     public Statement apply(Statement base, Description description) { 
      return new ExpansiveExternalResourceStatement(base); 

     } 


    } 
} 

Todo el trabajo de la regla se realiza en términos de una declaración. Un org.junit.runners.model.Statement es una clase que representa un paquete de código. Así que aquí el aplicar método recibe el paquete de código que está poniendo un shell. Aplicar devuelve su extracto que ejecuta el paquete de código que le dio y lo rodea con una instrucción try/catch para detectar las fallas del método.

La salida de este método es:

I am beforeclass 
I am before 
I am a Test 
I am after 
I am before 
I am a Failed Test 
I take a Screenshot 
I am after 
I am afterclass 

Espero que esto ayude!

+0

Troy, gracias por tu comentario. Tiene sugerencias de su solución. –

+0

Sugiero que se agregue el método '@ After' con la salida para que sea visible, que baseStatement.evaluate() en realidad causa' @ Before', luego prueba el método, luego '@ After' para ejecutar. – dhblah

1

¿Qué pasa con el uso de la regla ExternalResource?
Parece que puede darle suficiente flexibilidad a lo que necesita.
Y si esto no es exactamente lo que necesita, eche un vistazo al source code del recurso externo.
Es bastante entendible cómo implementar una regla, por ejemplo, que funcionará solo después de la invocación de la prueba.

4
public class ScreenshotTestRule implements MethodRule { 
    public Statement apply(final Statement statement, final FrameworkMethod frameworkMethod, final Object o) { 
     return new Statement() { 
      @Override 
      public void evaluate() throws Throwable { 
       try { 
        statement.evaluate(); 

       } catch (Throwable t) { 
        captureScreenshot(frameworkMethod.getName()); 
        throw t; // rethrow to allow the failure to be reported to JUnit      
       } finally { 
        tearDown(); 
       } 
      } 

      public void tearDown() { 
       //logout to the system; 
      } 


      public void captureScreenshot(String fileName) { 
       try { 
        new File("target/surefire-reports/screenshot").mkdirs(); // Insure directory is there 
        FileOutputStream out = new FileOutputStream("target/surefire-reports/screenshot/screenshot-" + fileName + ".png"); 
        out.write(((TakesScreenshot) driver).getScreenshotAs(OutputType.BYTES)); 
        out.close(); 
       } catch (Exception e) { 
        // No need to crash the tests if the screenshot fails 
       } 
      } 
     }; 
    } 
} 
Cuestiones relacionadas