2012-08-22 36 views
15

我有一个测试套件,我在@After之外注销系统并关闭@AfterClass中的浏览器。我试图使用@Rule针对每种测试方法使用Selenium进行失败的测试截图。我手动检查过@Rule只在每个@Before之前运行,但我想在@Test之后和@After之前设置它。我无法找到简单的解决方案。任何帮助将不胜感激。在每个'@Test'之后和JUnit中的每个'@After'之前应用'@Rule'

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

我得到的输出是关于使用ExternalResource规则

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

我提到过我只想在拍摄测试失败时才拍摄屏幕截图。不是每个测试:D –

+0

有趣。我只对订单感兴趣,所以其实你的问题是我的回答:) –

+0

@GáborLipták:)我很高兴! –

回答

19

由于设置规则的方式,您不能在@before之后或@after之前出现规则。你可以考虑像放在测试方法上的shell这样的规则。继续的第一个shell是/ @之后的@。此后,@rules被应用。

一个快速的方法来做你想做的是完全避免@After。可以创建一个规则,以便在方法失败时执行屏幕截图,然后在代码之后执行您的屏幕截图。它不像@After那么漂亮,但它有效。 (我也执行了TestRule,因为MethodRule已被折旧)。

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

     } 


    } 
} 

所有规则的工作是在一份声明中完成的。 org.junit.runners.model.Statement是一个代表一束代码的类。所以这里适用方法接收你正在放置一个shell的代码包。 Apply返回你的语句,它执行你给它的代码包,并用try/catch语句包围它以捕获方法失败。

此方法的输出是:

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 

希望这有助于!

+0

特洛伊,感谢您的评论。从您的解决方案中获得提示。 –

+0

我会建议在输出中添加'@ After'方法,这样它就可以看到,那baseStatement.evaluate()实际上会导致'@ Before',然后测试方法,然后'@ After'运行。 – dhblah

1

什么?
看起来像你它可以给你足够的灵活性,你需要什么。
如果这不完全符合您的需求,请查看外部资源的source code
如何实现一个仅在测试调用后才能工作的规则,这是非常容易理解的。

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 
       } 
      } 
     }; 
    } 
} 
相关问题