2012-08-22 19 views
15

Ho una suite di test in cui mi disconnetto dal sistema in @After e chiude il browser in @AfterClass. Sto cercando di utilizzare @Rule per eseguire uno screenshot di prova non riuscito utilizzando il selenio per ogni metodo di prova. Ho controllato manualmente che @Rule viene eseguito solo prima di ogni @Before ma desidero impostarlo dopo @Test e prima di @After. Non sono riuscito a trovare una soluzione semplice. Qualsiasi aiuto sarà apprezzato.Applicare '@Rule' dopo ogni '@Test' e prima di ogni '@Dopo' in 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; 
    }  
}    

L'uscita sto ottenendo è

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

Ho detto che voglio solo scattare una schermata solo quando un test fallisce. Non per ogni test: D –

+0

Divertente. Mi interessava solo l'ordine, quindi in realtà la tua domanda era la mia risposta :) –

+0

@ GáborLipták :) Sono contento! –

risposta

19

A causa del modo in cui vengono impostate le regole, non è possibile avere una regola che viene dopo @ prima o prima di @after. Puoi pensare a regole come le shell che hai inserito nel metodo di prova. La prima shell da avviare è @ before/@ after. Successivamente vengono applicate le regole @.

Un modo rapido per fare ciò che si vuole fare è evitare del tutto dopo. Una regola può essere creata in modo tale da richiedere uno screenshot se un metodo fallisce e quindi eseguire il tuo dopo il codice. Non è bello come @After, ma funziona. (Ho implementato anche TestRule perché MethodRule è stato ammortizzato).

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

     } 


    } 
} 

Tutto il lavoro della regola viene eseguito in una dichiarazione. A org.junit.runners.model.Statement è una classe che rappresenta un pacchetto di codice. Quindi, il metodo si applica al metodo per ricevere il pacchetto di codice su cui viene inserita una shell. Applica restituisce la dichiarazione che esegue il pacchetto di codice che gli hai fornito e lo circonda con un'istruzione try/catch per rilevare i fallimenti del metodo.

L'uscita per questo metodo è:

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 

Spero che questo aiuti!

+0

Troy, grazie per il tuo commento. Hai suggerimenti sulla tua soluzione. –

+0

Suggerirei di aggiungere il metodo '@ After' con l'output in modo che sia visibile, che baseStatement.evaluate() causi effettivamente' @ Before', quindi il metodo test, quindi '@ After' per l'esecuzione. – dhblah

1

Cosa succede ad usare la regola ExternalResource?
Sembra che tu possa darti abbastanza flessibilità per quello che ti serve.
E se questo non è esattamente quello che ti serve, dai un'occhiata allo source code della risorsa esterna.
È abbastanza comprensibile come implementare una regola, ad esempio che funzionerà solo dopo l'invocazione di test.

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