2014-09-29 70 views
18

我想停止并标记为失败太久,运行junit测试(在Maven 3 build中执行)。我知道的三种方法做的:标记为失败,运行时间过长JUnit测试

1)使用测试注释与超时参数:

@Test(timeout=100) 
public void testWithTimeout() { 
    ... 
} 

2)使用规则注释:

@Rule 
public Timeout globalTimeout = new Timeout(100); 

3)配置Maven的surefire-插件使用以下选项:

forkedProcessTimeoutInSeconds=1 
reuseForks=false 

线索是1)和2)需要更改每个测试(它当你有成千上万的人时会感到痛苦)。 3)解决方案是不可接受的,因为在许多模块中,第一次测试开始时测试使用的上下文 - 测试性能会急剧下降。

你有什么其他的想法如何实现?任何棘手的解决方案(不涉及修补JUnit :))?

+0

我的第一个问题是,你的单元测试会导致如此之多的超时?这听起来像你可能实际上正在执行集成或验收测试。 – 2014-09-29 20:19:36

+0

的确,你是对的。请注意,我没有提到我正在使用单元测试。 JUnit被用作集成和功能测试的基础框架。 – 2014-09-29 20:22:48

+2

不,但Maven一般会推荐Failsafe进行集成/功能测试 - 您可能会在那里找到更好的选择。 – 2014-09-29 20:53:20

回答

0

实际上超时规则对类中的所有测试方法应用相同的超时。

如果您不想将其添加到每个Test类,则可以在Test基类中定义它一次。

的东西,并不需要更改所有类,你可以实现一个Junit的定制套件亚军(见第二个代码示例)只是为了好玩

如何使用不推荐使用Thread.stop方法本哈克解决方案?

在函数为每个测试启动一个观察器线程之前,超时后将杀死Junit测试线程。

如果测试完成,则清除杀死观察者线程。

适用于这个小演示,不知道这是否会在生产规模上工作。

import static org.junit.Assert.*; 

import org.junit.After; 
import org.junit.Before; 
import org.junit.Test; 

// You could also make this a base class for test classes 
public class TimeoutTest { 

    Thread watcherThread ; 
    Thread junitTestThread; 
    final static int testTimeout = 2000; 

    @Before 
    public void myInit() 
    { 
     junitTestThread = Thread.currentThread(); 
     watcherThread = new Thread() 
     { 
      @Override 
      public void run() 
      { 
        try { 
         Thread.sleep(testTimeout); 
         junitTestThread.stop(); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
      } 
     }; 
     watcherThread.start(); 
    } 

    @After 
    public void myCleanup() throws InterruptedException 
    { 
     watcherThread.stop(); 
    } 

    @Test 
    public void testPassingFastTest() throws InterruptedException { 
     Thread.sleep(1000); 
    } 

    @Test 
    public void testFailingSlowTest() throws InterruptedException { 
     Thread.sleep(3000); 
    } 

} 

或者使用一套几测试类做到这一点:

import java.util.Arrays; 

import org.junit.runner.Description; 
import org.junit.runner.RunWith; 
import org.junit.runner.notification.RunListener; 
import org.junit.runner.notification.RunNotifier; 
import org.junit.runners.Suite; 
import org.junit.runners.Suite.SuiteClasses; 
import org.junit.runners.model.InitializationError; 
import org.junit.runners.model.RunnerBuilder; 

@RunWith(AllTests.class) 
public class AllTests extends Suite{ 

    Thread watcherThread ; 
    Thread junitTestThread; 
    final static int testTimeout = 70; 

    public AllTests(final Class<?> clazz) throws InitializationError { 
     super(clazz, findClasses()); 
     } 

    private static Class<?>[] findClasses() { 
     // You could write code here to get the list of all test classes from specific directories 
     return new Class<?>[] {TimeoutTest.class,TimeoutTest2.class}; 
     } 


    @Override 
    public void run(final RunNotifier notifier) { 


     notifier.addListener(new RunListener() { 
     @Override 
     public void testStarted(final Description description) {    
      System.out.println("Before test " + description.getDisplayName()); 
      junitTestThread = Thread.currentThread(); 
      watcherThread = new Thread() 
      { 
       @Override 
       public void run() 
       { 
         try { 
          Thread.sleep(testTimeout); 
          junitTestThread.stop(); 
         } catch (InterruptedException e) { 
          // TODO Auto-generated catch block 
          e.printStackTrace(); 
         } 
       } 
      }; 
      watcherThread.start(); 

     } 

     @Override 
     public void testFinished(final Description description) { 
      System.out.println("After test " + description.getDisplayName()); 
      watcherThread.stop(); 

     } 

     } 
    ); 

    super.run(notifier); 


    }  
} 
+0

另外,如果您的测试类具有公共基类,则可以将该代码添加到该类的Before和After之后 – 2014-10-01 01:02:56

0

也许不太你正在寻找的解决方案,但如果你有一个持续构建服务器运行测试,有通常是该作业的全局超时。 e.g. for Jenkins

2

您可以尝试通过编写扩展BlockJunit4ClassRunner的类来定义您自己的测试运行器,并且如果测试执行超出定义的超时时间,则会失败。 然后使用@RunWith(CustomizedTestRunner.class)注释您的测试类 您仍然需要修改类,但可以在单个位置指定超时值。

+0

我同意。我一直创建一个自定义运行器来集中测试配置,并获得好的结果! – 2014-10-27 12:14:40