In JUnit 5, repeated tests are written using the @RepeatedTest annotation.
A repeated test runs the same test method multiple times without requiring different input values.
Basic Example
import org.junit.jupiter.api.RepeatedTest;
import static org.junit.jupiter.api.Assertions.assertTrue;
class RandomNumberTest {
@RepeatedTest(5)
void randomNumberShouldBeLessThanTen() {
int number = (int) (Math.random() * 10);
assertTrue(number >= 0 && number < 10);
}
}
This test runs 5 times.
Difference Between @Test and @RepeatedTest
Instead of writing:
import org.junit.jupiter.api.Test;
class ExampleTest {
@Test
void shouldRunOnce() {
// test logic
}
}
You write:
import org.junit.jupiter.api.RepeatedTest;
class ExampleTest {
@RepeatedTest(3)
void shouldRunThreeTimes() {
// test logic
}
}
Access the Current Repetition
JUnit can inject a RepetitionInfo parameter into a repeated test. This lets you know which repetition is currently running.
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.RepetitionInfo;
import static org.junit.jupiter.api.Assertions.assertTrue;
class RetryExampleTest {
@RepeatedTest(5)
void repeatedTestWithInfo(RepetitionInfo repetitionInfo) {
int current = repetitionInfo.getCurrentRepetition();
int total = repetitionInfo.getTotalRepetitions();
System.out.println("Running repetition " + current + " of " + total);
assertTrue(current >= 1);
assertTrue(current <= total);
}
}
Example output:
Running repetition 1 of 5
Running repetition 2 of 5
Running repetition 3 of 5
Running repetition 4 of 5
Running repetition 5 of 5
Customize the Display Name
You can customize the name shown for each repeated test invocation.
import org.junit.jupiter.api.RepeatedTest;
class LoginTest {
@RepeatedTest(value = 3, name = "Login attempt {currentRepetition} of {totalRepetitions}")
void loginShouldSucceedRepeatedly() {
// test login logic
}
}
This may display as:
Login attempt 1 of 3
Login attempt 2 of 3
Login attempt 3 of 3
Common placeholders are:
{displayName}
{currentRepetition}
{totalRepetitions}
JUnit also provides predefined formats:
@RepeatedTest(value = 3, name = RepeatedTest.SHORT_DISPLAY_NAME)
or:
@RepeatedTest(value = 3, name = RepeatedTest.LONG_DISPLAY_NAME)
Example with @BeforeEach
Lifecycle methods such as @BeforeEach run before each repetition.
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.RepeatedTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CounterTest {
private int counter;
@BeforeEach
void setUp() {
counter = 0;
}
@RepeatedTest(3)
void counterStartsAtZeroEachTime() {
assertEquals(0, counter);
counter++;
}
}
Because @BeforeEach runs before every repetition, the counter starts at 0 each time.
When to Use Repeated Tests
Use @RepeatedTest when you want to run the same test multiple times, for example:
- testing code that uses random values
- checking for flaky behavior
- verifying repeated operations
- testing concurrency-related code
- making sure state is reset between runs
@RepeatedTest vs Parameterized Tests
Use @RepeatedTest when the test logic is the same and the input does not change.
Use parameterized tests when you want to run the same test with different inputs.
@RepeatedTest(5)
void sameTestRepeatedSeveralTimes() {
// same input or generated input each time
}
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void sameTestWithDifferentValues(int value) {
// runs once for each value
}
Maven Dependency
Make sure JUnit Jupiter is available in your project:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.13.4</version>
<scope>test</scope>
</dependency>
Gradle Dependency
testImplementation 'org.junit.jupiter:junit-jupiter:5.13.4'
test {
useJUnitPlatform()
}
Summary
Use @RepeatedTest to run the same test multiple times:
import org.junit.jupiter.api.RepeatedTest;
class ExampleTest {
@RepeatedTest(5)
void shouldRunFiveTimes() {
// test logic
}
}
A repeated test is useful when you need the same test executed more than once, while a parameterized test is better when each run needs different input data.
