如何为JUnit测试用例运行启用全局超时?

时间:2018-05-08 08:22:57

标签: java junit timeout junit4 junit5

这个question建议使用@Test批注的timeout参数让JUnit在超时后强制停止测试。

但到目前为止,我们已经完成了5000次单元测试,我们希望建立一个策略,要求开发人员从不发布需要10秒以上才能完成的测试。该政策可能会说"目标是< 10秒",但是我们希望确保在30秒后停止任何测试。 (这些数字只是一些例子,我们的想法是定义一些东西,足够好"对于大多数用例,但这也确保事情不会运行"永远")

现在,我想知道是否有办法启用此类行为,而转入每个测试用例并添加该注释参数。

现有的question也没有帮助:我正在寻找一次更改来启用此功能,而不是每个测试类一次更改解决方案。一个中央的全球开关。每个文件或方法不是一个。

3 个答案:

答案 0 :(得分:4)

虽然JUnit Jupiter(即JUnit 5中引入的编程和扩展模型)还没有内置 support for global timeouts,但您仍然可以自己实现全局超时支持。

唯一的问题是,超时扩展目前无法预先中止测试执行。换句话说,JUnit Jupiter中的超时扩展当前只能执行测试,如果执行时间太长(即等待测试结束后,如果测试挂起)。

在任何情况下,如果你想实现一个非抢占式全局超时扩展以与JUnit Jupiter一起使用,这就是你需要做的。

  1. 查看“JUnit 5用户指南”中的TimingExtension示例以获取灵感。您需要与此类似的代码,但如果duration超出配置的timeout,您将需要抛出异常。如何配置全局超时取决于您:硬编码,从JVM系统属性中查找值,从自定义注释中查找值等。
  2. 使用Java的ServiceLoader机制注册您的全局超时扩展。有关详细信息,请参阅Automatic Extension Registration
  3. 快乐测试!

答案 1 :(得分:2)

您可能正在寻找的内容尚未实施:https://github.com/junit-team/junit4/issues/140

虽然,您可以通过简单的继承获得相同的结果。

使用以下@Rule字段定义一个抽象父类,如 BaseIntegrationTest

public abstract class BaseIntegrationTest extends RunListener {

    private static final int TEST_GLOBAL_TIMEOUT_VALUE = 10;

    @Rule
    protected Timeout globalTimeout = Timeout.seconds(TEST_GLOBAL_TIMEOUT_VALUE);

}

然后将其作为范围内每个测试类的父级。例如:

public class BaseEntityTest extends BaseIntegrationTest {

    @Before
    public void init() {
        // init
    }

    @Test
    public void twoPlusTwoTest() throws Exception {
        assert 2 + 2 == 4;        
    }
}

那就是它。

答案 2 :(得分:2)

签出我的JUnit 4扩展库(https://github.com/Nordstrom/JUnit-Foundation)。该库提供的功能包括定义全局超时值的功能,该值将自动应用于尚未定义较长超时间隔的每个测试方法。

该库使用字节伙伴字节代码生成库在JUnit 4的测试执行流程中的关键点安装事件挂钩。当JUnit创建测试类实例以运行“原子”测试时,将应用全局超时。

要应用全局超时,该库将原始@Test注释替换为实现@Test接口的对象。这种方法利用了JUnit的所有本机超时功能,该功能可抢先终止运行时间过长的测试。使用本机超时功能无需进行侵入式实现或特殊情况处理,并且无需触摸单个源文件即可激活此功能。

安装和激活全局超时支持所需的所有更新都在项目文件(POM / build.gradle)和可选属性文件中。可以通过“系统”属性覆盖超时间隔,该属性使您可以从命令行或以编程方式进行调整。对于因瞬态情况导致超时失败的情况,您可能需要将全局超时功能与自动重试功能配对。