java 在 JUnit 中的每个“@Test”之后和每个“@After”之前应用“@Rule”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12078982/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Apply '@Rule' after each '@Test' and before each '@After' in JUnit
提问by Reaz Patwary
I have a test suite where I am logging out of the system in @After
and closing the browser in @AfterClass
. I am trying to use @Rule
to take failed test screenshot using Selenium for every test method. I checked manually that @Rule
only runs before every @Before
but I want to set it up after @Test
and before @After
. I couldn't find out simple solution. Any help will be appreciated.
我有一个测试套件,我在其中注销系统@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;
}
}
The output I am getting is
我得到的输出是
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
回答by Troy
Because of the way that rules are set up, you can't have a rule that comes after @before or before @after. You can think of rules like shells that you put on the test method. The first shell to go on is @before/@after. Thereafter the @rules are applied.
由于规则的设置方式,您不能有在@before 之后或@after 之前的规则。您可以将规则想象为放置在测试方法上的外壳。要进行的第一个 shell 是@before/@after。此后应用@rules。
A quick way to do what you want to do is to avoid @After altogether. A rule can be created so that it will take a screenshot if a method fails and then execute yours after the code. It isn't quite as pretty as @After, but it works. (also I implemented TestRule because MethodRule has been depreciated).
做你想做的事情的一个快速方法是完全避免@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);
}
}
}
All the work of the rule is done in a statement. A org.junit.runners.model.Statement is a class that represents a bundle of code. So here the applymethod receives the bundle of code that you are putting a shell around. Apply returns your statement that executes the bundle of code that you gave it and surrounds it with a try/catch statement to catch the method failures.
规则的所有工作都在一个语句中完成。org.junit.runners.model.Statement 是一个表示一组代码的类。所以这里的apply方法接收你放置一个shell 的代码包。Apply 返回执行您提供给它的代码包的语句,并用 try/catch 语句包围它以捕获方法失败。
The output for this method is:
此方法的输出是:
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
Hope this helps!
希望这可以帮助!
回答by Reaz Patwary
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
}
}
};
}
}
回答by Yair Zaslavsky
What about using the ExternalResourcerule ?
Looks like you it can give you enough flexibility to what you need.
And if this is not exactly what you need, take a look at the source codeof external resource.
It's quite understandble how to implement a rule for example that will work only after the test invocation.
使用ExternalResource规则怎么样?
看起来你它可以给你足够的灵活性来满足你的需要。
如果这不是您所需要的,请查看外部资源的源代码。
例如,如何实现仅在测试调用后才起作用的规则是完全可以理解的。