在 JUnit 中每次'@Test'之后和每次'@After'之前应用 '@Rule'



我有一个测试套件,在@After中注销系统,并在@AfterClass中关闭浏览器。我正在尝试使用@Rule对每种测试方法使用Selenium来拍摄失败的测试屏幕截图。我手动检查了@Rule只在每个@Before之前运行,但我想在@Test之后和@After之前设置它。我找不到简单的解决办法。任何帮助都将不胜感激。

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

我得到的输出是

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

由于规则的设置方式,您不能有一个位于@before或@after之前的规则。你可以把规则想象成你放在测试方法上的shell。第一个继续的shell是before/after。然后应用@规则。

做你想做的事的一个快速方法是完全避免@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.unit.runners.model.Statement是一个表示代码束的类。因此,apply方法在这里接收您放置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

希望这能有所帮助!

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

使用ExternalResource规则怎么样
看起来你可以给你足够的灵活性来满足你的需求
如果这不是您所需要的,请查看外部资源的源代码
例如,如何实现一个只有在测试调用后才能工作的规则是很容易理解的

最新更新