Labs ICT
โญ Pro Login

Testing with @Timeout

Sometimes you need to make sure a method does not run forever. Maybe it calls an external API, processes a large file, or does some computation that should not take too long. JUnit 5's @Timeout annotation lets you set time limits on your tests.

Basic @Timeout Usage


import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.Test;
import java.util.concurrent.TimeUnit;

class TimeoutTest {

    @Test
    @Timeout(5)  // 5 seconds
    void shouldCompleteWithinFiveSeconds() {
        // If this takes more than 5 seconds, test fails
        int result = heavyComputation();
        assertEquals(42, result);
    }

    @Test
    @Timeout(value = 500, unit = TimeUnit.MILLISECONDS)
    void shouldCompleteWithin500Millis() {
        // More precise control
        String result = quickOperation();
        assertNotNull(result);
    }

    @Test
    @Timeout(value = 1, unit = TimeUnit.MINUTES)
    void shouldCompleteWithinOneMinute() {
        // Long-running test with generous timeout
        processData();
    }
}
    

Timeout with assertTimeout

assertTimeout is an alternative that works inline:


import org.junit.jupiter.api.Test;
import java.time.Duration;

class InlineTimeoutTest {

    @Test
    void shouldCompleteWithinTimeout() {
        assertTimeout(Duration.ofSeconds(2), () -> {
            // This entire block must complete within 2 seconds
            int result = compute();
            assertEquals(100, result);
        });
    }

    @Test
    void shouldCompleteWithinMillis() {
        assertTimeout(Duration.ofMillis(500), () -> {
            quickTask();
        });
    }
}
    

@Timeout on Class Level

You can set a timeout for the entire test class:


@Test
@Timeout(value = 30, unit = TimeUnit.SECONDS)
class AllTestsMustBeFastTest {

    @Test
    void test1() { /* ... */ }

    @Test
    void test2() { /* ... */ }

    @Test
    void test3() { /* ... */ }
}
    

If the total execution time of all tests exceeds 30 seconds, the class-level timeout kicks in.

Timeout Modes

@Timeout has two modes:


// FAIL mode (default) - test fails if timeout exceeded
@Test
@Timeout(value = 5, unit = TimeUnit.SECONDS)
void failsOnTimeout() {
    // ...
}

// INTERRUPT mode - thread is interrupted on timeout
@Test
@Timeout(value = 5, unit = TimeUnit.SECONDS, threadMode =
    Timeout.ThreadMode.SEPARATE_THREAD)
void interruptsOnTimeout() {
    // Runs in a separate thread, interrupted on timeout
}
    

When to Use Timeouts

  • Testing methods that call external services
  • Ensuring algorithms complete in reasonable time
  • Preventing tests from hanging indefinitely
  • Performance regression tests
  • Verifying async operations complete

@Test
@Timeout(value = 10, unit = TimeUnit.SECONDS)
void shouldProcessLargeDataset() {
    DataSet data = loadLargeDataSet();
    Result result = processor.process(data);
    assertNotNull(result);
    assertTrue(result.isComplete());
}

@Test
void shouldCallExternalApi() {
    assertTimeout(Duration.ofSeconds(5), () -> {
        Response response = apiClient.getUsers();
        assertEquals(200, response.getStatusCode());
    });
}
    

Best Practices

  • Set realistic timeouts โ€” do not make them too tight
  • Use timeouts mainly for integration or external service tests
  • Unit tests should be fast enough to not need timeouts
  • Consider using SEPARATE_THREAD mode for reliable timeout enforcement
  • Combine with @Tag("slow") for tests that naturally take longer

๐Ÿงช Quick Quiz

What annotation sets a time limit for a test?