JUnit allows additional context to be injected into a repeated test method using RepetitionInfo. This enables the test logic to be aware of the current repetition information.
Definition of RepetitionInfoVersion: 6.0.0 package org.junit.jupiter.api;
@API(status = STABLE, since = "5.0")
public interface RepetitionInfo {
int getCurrentRepetition(); 1
int getTotalRepetitions(); 2
@API(status = MAINTAINED, since = "5.13.3")
int getFailureCount(); 3
@API(status = MAINTAINED, since = "5.13.3")
int getFailureThreshold(); 4
}
In this tutorial we will focus on getCurrentRepetition() and getTotalRepetitions() methods only.
Common Usage
While it’s easy to think of RepetitionInfo as just a way to label your console logs (e.g., "Running test 3 of 10"), its real power lies in controlling the logic and data of your test dynamically based on which iteration is currently running.
- Indexing Data: Use
repetitionInfo.getCurrentRepetition() to pick a specific element from a collection or array, allowing you to iterate through different data sets manually.
- Stateful Testing: Change assertions based on the iteration count, such as expecting success for the first few runs and a "Rate Limit" error once
getCurrentRepetition() exceeds a certain threshold.
- Progressive Stress: Increase the workload or complexity in each cycle by using the repetition number as a multiplier for the amount of data processed.
- Final Run Logic: Compare
getCurrentRepetition() with repetitionInfo.getTotalRepetitions() to trigger a specific final validation or resource cleanup only during the very last execution.
Comparison with @ParameterizedTest: While @ParameterizedTest is designed for injecting specific data sets into separate test runs, RepetitionInfo is used within a @RepeatedTest to dynamically alter logic, load, or assertions based on the current progress of the loop.
Example
Quick example how to use @RepetitionInfo
package com.logicbig.example;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class RepeatedTestWithRepetitionInfoExample {
@RepeatedTest(3)
void myTest(RepetitionInfo repetitionInfo) {
System.out.println("current repetition: " +
repetitionInfo.getCurrentRepetition());
System.out.println("total repetitions: " +
repetitionInfo.getTotalRepetitions());
System.out.println("failure count: " +
repetitionInfo.getFailureCount());
System.out.println("failure threshold " +
repetitionInfo.getFailureThreshold());
assertTrue(true);
}
}
Output$ mvn test -Dtest=RepeatedTestWithRepetitionInfoExample [INFO] Scanning for projects... [INFO] [INFO] --< com.logicbig.example:junit-5-repeated-test-with-repetition-info >--- [INFO] Building junit-5-repeated-test-with-repetition-info 1.0-SNAPSHOT [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-repeated-test-with-repetition-info --- [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-with-repetition-info\src\main\resources [INFO] [INFO] --- compiler:3.11.0:compile (default-compile) @ junit-5-repeated-test-with-repetition-info --- [INFO] No sources to compile [INFO] [INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-repeated-test-with-repetition-info --- [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-with-repetition-info\src\test\resources [INFO] [INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ junit-5-repeated-test-with-repetition-info --- [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-with-repetition-info --- [INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] +--com.logicbig.example.RepeatedTestWithRepetitionInfoExample - 0.309 ss [INFO] | +-- [OK] myTest(RepetitionInfo) repetition 1 of 3 - 0.104 ss [INFO] | +-- [OK] myTest(RepetitionInfo) repetition 2 of 3 - 0.014 ss [INFO] | '-- [OK] myTest(RepetitionInfo) repetition 3 of 3 - 0.003 ss [INFO] [INFO] Results: [INFO] [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 7.412 s [INFO] Finished at: 2025-12-26T13:38:57+08:00 [INFO] ------------------------------------------------------------------------
The output of this example confirms that each execution receives accurate repetition metadata. The test verifies that the current repetition number never exceeds the total number of repetitions. This demonstrates how RepetitionInfo can be used to implement repetition-aware assertions while keeping the test logic minimal and readable.
Another Example, Conditional Assertions using RepetitionInfo
package com.logicbig.example;
import org.junit.jupiter.api.*;
import java.util.ArrayDeque;
import java.util.NoSuchElementException;
import java.util.Queue;
class QueueTest {
// Shared state for the repetitions
static Queue<String> queue = new ArrayDeque<>();
@BeforeAll
static void setup() {
queue.add("Task 1");
queue.add("Task 2");
queue.add("Task 3");
}
@RepeatedTest(5)
void testQueueDepletion(RepetitionInfo repetitionInfo) {
if (repetitionInfo.getCurrentRepetition() <= 3) {
// First 3 runs: Queue has items
System.out.println("success test");
Assertions.assertDoesNotThrow(() -> queue.remove(),
"Should not fail on repetition " + repetitionInfo.getCurrentRepetition());
} else {
// 4th/5th run: Queue is empty, remove() throws NoSuchElementException
System.out.println("failure test");
Assertions.assertThrows(NoSuchElementException.class, () -> queue.remove(),
"Should throw error on repetition " + repetitionInfo.getCurrentRepetition());
}
}
}
Output$ mvn test -Dtest=QueueTest [INFO] Scanning for projects... [INFO] [INFO] --< com.logicbig.example:junit-5-repeated-test-with-repetition-info >--- [INFO] Building junit-5-repeated-test-with-repetition-info 1.0-SNAPSHOT [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-repeated-test-with-repetition-info --- [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-with-repetition-info\src\main\resources [INFO] [INFO] --- compiler:3.11.0:compile (default-compile) @ junit-5-repeated-test-with-repetition-info --- [INFO] No sources to compile [INFO] [INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-repeated-test-with-repetition-info --- [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-with-repetition-info\src\test\resources [INFO] [INFO] --- compiler:3.11.0:testCompile (default-testCompile) @ junit-5-repeated-test-with-repetition-info --- [INFO] Changes detected - recompiling the module! :input tree [WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent! [INFO] Compiling 2 source files with javac [debug target 17] to target\test-classes [INFO] [INFO] --- surefire:3.5.0:test (default-test) @ junit-5-repeated-test-with-repetition-info --- [INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- success test success test success test failure test failure test [INFO] +--com.logicbig.example.QueueTest - 0.106 ss [INFO] | +-- [OK] testQueueDepletion(RepetitionInfo) repetition 1 of 5 - 0.030 ss [INFO] | +-- [OK] testQueueDepletion(RepetitionInfo) repetition 2 of 5 - 0.001 ss [INFO] | +-- [OK] testQueueDepletion(RepetitionInfo) repetition 3 of 5 - 0.001 ss [INFO] | +-- [OK] testQueueDepletion(RepetitionInfo) repetition 4 of 5 - 0.005 ss [INFO] | '-- [OK] testQueueDepletion(RepetitionInfo) repetition 5 of 5 - 0.001 ss [INFO] [INFO] Results: [INFO] [INFO] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4.053 s [INFO] Finished at: 2025-12-26T15:06:54+08:00 [INFO] ------------------------------------------------------------------------
The output confirms that RepetitionInfo enables state-aware testing by synchronizing assertions with the changing state of the queue. By switching from "success" to "failure" logic at the exact moment the queue is exhausted, it proves that the tool's practical value lies in managing temporal logic across multiple iterations of a single test method.
Example ProjectDependencies and Technologies Used: - junit-jupiter-engine 6.0.1 (Module "junit-jupiter-engine" of JUnit)
Version Compatibility: 5.10.0 - 6.0.1 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
|