2011-08-08 81 views
26

如果在测试用例中出现测试失败或错误,JUnit是否有方法在@After注释方法内检测?在@After方法中检测Junit测试失败或错误

一个丑陋的解决办法是这样的:在测试代码

boolean withoutFailure = false; 

@Test 
void test() { 
    ... 
    asserts... 
    withoutFailure = true; 
} 

@After 
public void tearDown() { 
    if(!withoutFailuere) { 
     this.dontReuseTestenvironmentForNextTest(); 
    } 
} 

这是丑陋的,因为一个需要照顾的“基础设施”(withoutFailure标志)。

我希望有一些东西可以在@After方法中获得测试状态!?

+0

是不是你的'@ Before'方法以确保环境设置正确的每一个测试护理? –

+0

@Vineet Reynolds:是和否:我正在使用Selemium2/Webdriver进行测试,我想重新使用驱动程序。但是如果之前的测试没有任何错误,我只想重用。 – Ralph

+0

好的,我目前的问题。我试图避免国旗。希望看到其他答案。如果我遇到一个合理的解决方案,我会发布我的。 –

回答

8

如果你足够幸运能够使用JUnit 4.9或更高版本,TestWatcher将完全符合你的要求。

分享和享受!

+5

由于此帖后面的TestWatchman已被弃用,TestWatcher是新的类。 – jconlin

+0

链接现已停止。 –

+3

这不适用于JUnit 4.12和Arquillian 1.1.10,因为TestWatcher会在执行'@ After'方法后得到失败的通知。 –

2

我想你要做的是在JUnit内核中添加RunListener。然后,您可以覆盖testFailure方法,将您的withoutFailure标志设置在一个位置,以便您可以在您的@After带注释的方法中检查它。

另请参阅:this blog post,以便在使用早期版本的JUnit时讨论此方法的一些问题。

1

我扩展了dsaff的答案,以解决TestRule无法在测试方法执行和后续方法执行之间执行某些代码的问题。因此,使用简单的MethodRule,不能使用此规则提供在@After带注释的方法中使用的成功标志。

我的想法是黑客!无论如何,这是使用TestRule(延伸TestWatcher)。 A TestRule将获得有关测试失败或成功的知识。然后,我的TestRule将扫描该类中所有用我的新AfterHack批注注释的方法,并使用成功标志调用该方法。


AfterHack注释

import static java.lang.annotation.ElementType.METHOD; 
import static java.lang.annotation.RetentionPolicy.RUNTIME;  
import java.lang.annotation.Retention; 
import java.lang.annotation.Target; 

@Retention(RUNTIME) 
@Target(METHOD) 
public @interface AfterHack {} 

AfterHackRule

import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.util.ArrayList; 
import java.util.List; 

import org.junit.rules.TestWatcher; 
import org.junit.runner.Description; 

public class AfterHackRule extends TestWatcher { 

    private Object testClassInstance; 
    public AfterHackRule(final Object testClassInstance) { 
     this.testClassInstance = testClassInstance; 
    } 

    protected void succeeded(Description description) { 
     invokeAfterHackMethods(true); 
    } 

    protected void failed(Throwable e, Description description) { 
     invokeAfterHackMethods(false); 
    } 

    public void invokeAfterHackMethods(boolean successFlag) { 
     for (Method afterHackMethod : 
        this.getAfterHackMethods(this.testClassInstance.getClass())) { 
      try { 
       afterHackMethod.invoke(this.testClassInstance, successFlag); 
      } catch (IllegalAccessException | IllegalArgumentException 
        | InvocationTargetException e) { 
       throw new RuntimeException("error while invoking afterHackMethod " 
          + afterHackMethod); 
      } 
     } 
    } 

    private List<Method> getAfterHackMethods(Class<?> testClass) { 
     List<Method> results = new ArrayList<>();    
     for (Method method : testClass.getMethods()) { 
      if (method.isAnnotationPresent(AfterHack.class)) { 
       results.add(method); 
      } 
     } 
     return results; 
    } 
} 

用法:

public class DemoTest { 

    @Rule 
    public AfterHackRule afterHackRule = new AfterHackRule(this); 

    @AfterHack 
    public void after(boolean success) { 
     System.out.println("afterHack:" + success); 
    } 

    @Test 
    public void demofails() { 
     Assert.fail(); 
    } 

    @Test 
    public void demoSucceeds() {} 
} 

顺便说一句:

  • 1)希望有在Junit5
  • 更好的解决方案
  • 2)更好的方法是在所有使用规则TestWatcher代替@Before和@After方法的(即我读dsaff的答案的方式)

@see

1

我不知道任何简单的或优雅的方式来检测的方法@After JUnit测试失败。

如果可以使用TestRule而不是@After方法,则可以使用两个链接的TestRules,使用TestWatcher作为内部规则。

例子:

package org.example; 

    import static org.junit.Assert.fail; 

    import org.junit.Rule; 
    import org.junit.Test; 
    import org.junit.rules.ExternalResource; 
    import org.junit.rules.RuleChain; 
    import org.junit.rules.TestRule; 
    import org.junit.rules.TestWatcher; 
    import org.junit.runner.Description; 

    public class ExampleTest { 

     private String name = ""; 
     private boolean failed; 

     @Rule 
     public TestRule afterWithFailedInformation = RuleChain 
     .outerRule(new ExternalResource(){ 
      @Override 
      protected void after() { 
      System.out.println("Test "+name+" "+(failed?"failed":"finished")+"."); 
      }  
     }) 
     .around(new TestWatcher(){ 
      @Override 
      protected void finished(Description description) { 
      name = description.getDisplayName(); 
      } 
      @Override 
      protected void failed(Throwable e, Description description) { 
      failed = true; 
      }  
     }) 
     ; 

     @Test 
     public void testSomething(){ 
     fail(); 
     } 

     @Test 
     public void testSomethingElse(){ 
     } 

    } 
+0

但是,当我能够使用TestRule而不是@After时,那么我可以使用TestRule并且不需要'RuleChain' - 或者我错过了什么? – Ralph

+0

RuleChain ...部分通过将两个规则“连接”在一起(TestWatcher和ExternalResource)构造一个新的TestRule。您可以独立指定这些规则,但是可能会发生after()方法在failed()之前执行的情况。 System.out.println()部分是您将放入相应的@After方法中的部分。 – Gustave

+0

我不明白的是:为什么我不应该简单地使用它在测试之后运行的'TestWatcher',并且有''succeeded'方法和''failed''方法? – Ralph