2012-08-22 3 views
15

Ich habe eine Testsuite, wo ich mich aus dem System in @After abmelden und den Browser in @AfterClass schließen. Ich versuche, @Rule zu verwenden, um gescheitertes TestScreenshot unter Verwendung Selenium für jede Testmethode zu nehmen. Ich habe manuell überprüft, dass @Rule nur vor jedem @Before läuft, aber ich möchte es nach @Test und vor @After einrichten. Ich konnte keine einfache Lösung finden. Jede Hilfe wird geschätzt.Wenden Sie '@Rule' nach jedem '@Test' und vor jedem '@After' 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; 
    }  
}    

Der Ausgang ich immer bin, ist

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

Ich erwähnte ich will nur Screenshot nur wenn ein Test fehlschlagen. Nicht für jeden Test: D –

+0

Lustig. Ich war nur an der Bestellung interessiert, also war deine Frage eigentlich meine Antwort :) –

+0

@ GáborLipták :) Ich bin froh! –

Antwort

19

Aufgrund der Art und Weise, wie Regeln eingerichtet werden, können Sie keine Regel haben, die nach @before oder before @after kommt. Sie können sich Regeln wie Shells vorstellen, die Sie auf die Testmethode anwenden. Die erste Shell ist @ davor/@ danach. Danach werden die @ Regeln angewendet.

Ein schneller Weg zu tun, was Sie tun möchten, ist @After ganz zu vermeiden. Es kann eine Regel erstellt werden, so dass ein Screenshot erstellt wird, wenn eine Methode fehlschlägt, und anschließend eine nach dem Code ausgeführt wird. Es ist nicht ganz so schön wie @After, aber es funktioniert. (Ich habe auch TestRule implementiert, da MethodRule abgeschrieben wurde).

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

     } 


    } 
} 

Die ganze Arbeit der Regel wird in einer Aussage getan. Eine org.junit.runners.model.Statement ist eine Klasse, die ein Code-Paket darstellt. Also hier die gelten Methode erhält das Bündel von Code, den Sie eine Shell um setzen. Apply gibt Ihre Anweisung zurück, die das von Ihnen angegebene Code-Paket ausführt und es mit einer try/catch-Anweisung umgibt, um die Methodenfehler abzufangen.

Die Ausgabe für diese Methode ist:

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 

hoffe, das hilft!

+0

Troy, Danke für Ihren Kommentar. Bekomme Hinweise von deiner Lösung. –

+0

Ich würde vorschlagen, '@ After' Methode mit Ausgabe hinzuzufügen, so dass es sichtbar sein wird, dass baseStatement.evaluate() tatsächlich' @ Before' verursacht, dann Testmethode, dann '@ After' zu laufen. – dhblah

1

Was die ExternalResource Regel?
Sieht aus wie Sie es Ihnen geben kann genug Flexibilität, was Sie brauchen.
Und wenn das nicht genau das ist, was Sie brauchen, werfen Sie einen Blick auf die source code der externen Ressource.
Es ist ziemlich verständlich, wie zum Beispiel eine Regel implementiert wird, die nur nach dem Testaufruf funktioniert.

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