Close

JUnit 5 - @RepeatedTest, working with failure count

[Last Updated: Dec 27, 2025]

@RepeatedTest is commonly used to run the same test logic multiple times, but it becomes far more practical when combined with repetition metadata that can track failures across repetitions. In newer JUnit versions, repetition-aware APIs allow a test to react with failures counts.

This is particularly useful for validating retry-like behavior, flaky integrations, or stability-sensitive logic where occasional failure is tolerated but persistent failure should abort further repetitions.

Use Cases

  • Intelligent retries
    Adjust test behavior based on how many previous attempts have failed (for example, retry normally at first, then change strategy).
  • Progressive diagnostics
    Enable additional logging, tracing, or state dumps only after one or more failures to reduce noise and overhead.
  • Fail-fast thresholds
    Abort or short-circuit further meaningful work once a defined number of failures has been reached.
  • Backoff or stabilization logic
    Increase delays, timeouts, or waits after repeated failures when testing unstable or eventually consistent systems.
  • Adaptive assertions
    Start with relaxed checks and enforce stricter assertions only if failures continue.
  • Flaky test characterization
    Differentiate transient failures from persistent ones by observing how quickly failures accumulate across repetitions.

Example

package com.logicbig.example;

import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import org.opentest4j.TestAbortedException;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class ProgressiveRetryTest {

    @RepeatedTest(5)
    void flakyOperation(RepetitionInfo repetitionInfo) {
        System.out.println("Current repetition: " +
                                   repetitionInfo.getCurrentRepetition());
        int failuresSoFar = repetitionInfo.getFailureCount();

        if (failuresSoFar == 1) {
            //Simulate enabling debug logs
            System.out.println("Second attempt: enabled debug logging");
        }

        if (failuresSoFar == 2) {
            System.out.println("Aborting repetition");
            throw new TestAbortedException(
                    "Aborting remaining repetitions after " + failuresSoFar + " failures"
            );
        }

        // Simulate a flaky operation
        System.out.println("Performing flaky test");
        assertTrue(false);
    }
}

Output

$ mvn test -Dtest=ProgressiveRetryTest
[INFO] Scanning for projects...
[INFO]
[INFO] ------< com.logicbig.example:junit-5-repeated-test-failure-count >------
[INFO] Building junit-5-repeated-test-failure-count 1.0-SNAPSHOT
[INFO] from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-repeated-test-failure-count ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-repeated-tests\junit-5-repeated-test-failure-count\src\main\resources
[INFO]
[INFO] --- compiler:3.11.0:compile (default-compile) @ junit-5-repeated-test-failure-count ---
[INFO] No sources to compile
[INFO]
[INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-repeated-test-failure-count ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-repeated-tests\junit-5-repeated-test-failure-count\src\test\resources
[INFO]
[INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ junit-5-repeated-test-failure-count ---
[INFO] Changes detected - recompiling the module! :source
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 1 source file with javac [debug target 17] to target\test-classes
[INFO]
[INFO] --- surefire:3.5.0:test (default-test) @ junit-5-repeated-test-failure-count ---
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
Current repetition: 1
Performing flaky test
Current repetition: 2
Second attempt: enabled debug logging
Performing flaky test
Current repetition: 3
Aborting repetition
Current repetition: 4
Aborting repetition
Current repetition: 5
Aborting repetition
[INFO] +--com.logicbig.example.ProgressiveRetryTest - 0.226 ss
[INFO] | +-- [XX] flakyOperation(RepetitionInfo) repetition 1 of 5 - 0.105 ss
[INFO] | +-- [XX] flakyOperation(RepetitionInfo) repetition 2 of 5 - 0.015 ss
[INFO] | +-- [??] flakyOperation(RepetitionInfo) repetition 3 of 5 - 0 ss
[INFO] | +-- [??] flakyOperation(RepetitionInfo) repetition 4 of 5 - 0 ss
[INFO] | '-- [??] flakyOperation(RepetitionInfo) repetition 5 of 5 - 0 ss
[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR] ProgressiveRetryTest.flakyOperation:30 expected: <true> but was: <false>
[ERROR] ProgressiveRetryTest.flakyOperation:30 expected: <true> but was: <false>
[INFO]
[ERROR] Tests run: 5, Failures: 2, Errors: 0, Skipped: 3
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.504 s
[INFO] Finished at: 2025-12-27T06:09:44+08:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.5.0:test (default-test) on project junit-5-repeated-test-failure-count: There are test failures.
[ERROR]
[ERROR] Please refer to D:\example-projects\junit-5\junit-5-repeated-tests\junit-5-repeated-test-failure-count\target\surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

The output shows that each @RepeatedTest repetition is executed as a separate invocation, while RepetitionInfo#getFailureCount() tracks the number of previous failed repetitions. The first run fails with a failure count of 0, the second run sees a failure count of 1 and enables additional diagnostics, and the third run sees a failure count of 2 and throws TestAbortedException. Although JUnit still calls the test method for repetitions 4 and 5, those invocations are immediately aborted and reported as skipped.

Example Project

Dependencies and Technologies Used:

  • junit-jupiter-engine 6.0.1 (Module "junit-jupiter-engine" of JUnit)
     Version Compatibility: 5.10.0 - 6.0.1Version List
    ×

    Version compatibilities of junit-jupiter-engine with this example:

    • 5.10.0
    • 5.10.1
    • 5.10.2
    • 5.10.3
    • 5.10.4
    • 5.10.5
    • 5.11.0
    • 5.11.1
    • 5.11.2
    • 5.11.3
    • 5.11.4
    • 5.12.0
    • 5.12.1
    • 5.12.2
    • 5.13.0
    • 5.13.1
    • 5.13.2
    • 5.13.3
    • 5.13.4
    • 5.14.0
    • 5.14.1
    • 6.0.0
    • 6.0.1

    Versions in green have been tested.

  • JDK 25
  • Maven 3.9.11

JUnit 5 - @RepeatedTest Failure Count Select All Download
  • junit-5-repeated-test-failure-count
    • src
      • test
        • java
          • com
            • logicbig
              • example
                • ProgressiveRetryTest.java

    See Also