How to timeout all tests in a class?

Viewed 89

I have 1000+ test cases loaded from file and run within file.

Since the tests can take overly long I introduced I timeout for all of them:

@ClassRule
public static Timeout classTimeout = new Timeout(200);

This was working fine in Junit4, but now, once I migrated the test to Junit5, I can see no support for @ClassRule.

There's @Timeout annotation but it works per test method.

1 Answers

I couldn't find functionality like this provided by junit, so i came up with a somewhat naive implementation to fail every test when cumulative execution time exceeds a limit.

What is needed:

  1. BeforeAllCallback.beforeAll()

Callback that is invoked once before all tests in the current container.

  1. BeforeTestExecutionCallback.beforeTestExecution()

Callback that is invoked immediately before an individual test is executed but after any user-defined setup methods have been executed for that test.

  1. AfterTestExecutionCallback.afterTestExecution()

Callback that is invoked immediately after an individual test has been executed but before any user-defined teardown methods have been executed for that test.

public class AllTestsTimeoutException implements BeforeAllCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback {

    private final long maxElapsedTimeNanos;
    private long start;

    public AllTestsTimeoutException(long maxElapsedTimeNanos) {
        this(maxElapsedTimeNanos, TimeUnit.NANOSECONDS);
    }

    public AllTestsTimeoutException(long value, TimeUnit timeUnit) {
        this.maxElapsedTimeNanos = timeUnit.toNanos(value);
    }

    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        start = System.nanoTime();
    }

    @Override
    public void beforeTestExecution(ExtensionContext context) throws Exception {
        checkElapsedTimes(context, "Before check");
    }

    private void checkElapsedTimes(ExtensionContext context, String prefix) {
        long elapsedNanos = System.nanoTime() - start;
        System.out.println(prefix + " - " + context.getRequiredTestMethod().getName() + " - " + elapsedNanos);
        if (context.getExecutionException().isEmpty() && elapsedNanos > maxElapsedTimeNanos) {
            throw new RuntimeException("all tests time out");
        }
    }

    @Override
    public void afterTestExecution(ExtensionContext context) throws Exception {
        checkElapsedTimes(context, "After check");
    }
}

It needs some polishing, but it can serve as starting point to improve from.

Registration is as a public static field in the class with RegisterExtension.

public class TimeoutTests {

    @RegisterExtension
    public static AllTestsTimeoutException timeout = new AllTestsTimeoutException(25, TimeUnit.MILLISECONDS);

    @Test
    public void test1() {
        //test stuff
    }

    @Test
    public void test2() {
        //test stuff
    }

    @Test
    public void test3() {
        //test stuff
    }
}
Related