In JUnit 5, @MethodSource lets you supply test arguments from one or more factory methods. It is commonly used with @ParameterizedTest when your test data is too complex for @ValueSource or @CsvSource.
Basic example
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertTrue;
class StringTest {
@ParameterizedTest
@MethodSource("blankStrings")
void shouldDetectBlankStrings(String input) {
assertTrue(input == null || input.isBlank());
}
static Stream<String> blankStrings() {
return Stream.of(null, "", " ", "\t", "\n");
}
}
The method referenced by @MethodSource("blankStrings") provides the test data.
Supplying multiple arguments
If your test method has multiple parameters, return Stream<Arguments>.
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
class CalculatorTest {
@ParameterizedTest
@MethodSource("additionCases")
void shouldAddNumbers(int a, int b, int expected) {
assertEquals(expected, a + b);
}
static Stream<Arguments> additionCases() {
return Stream.of(
Arguments.of(1, 2, 3),
Arguments.of(5, 7, 12),
Arguments.of(-1, 1, 0)
);
}
}
Using a method source without naming it
If the source method has the same name as the test method, you can omit the method name.
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertTrue;
class NumberTest {
@ParameterizedTest
@MethodSource
void isEven(int number) {
assertTrue(number % 2 == 0);
}
static Stream<Integer> isEven() {
return Stream.of(2, 4, 6, 8);
}
}
Dynamic test data
You can generate test data dynamically inside the provider method.
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.IntStream;
import static org.junit.jupiter.api.Assertions.assertTrue;
class RangeTest {
@ParameterizedTest
@MethodSource("numbersFromOneToTen")
void shouldBePositive(int number) {
assertTrue(number > 0);
}
static IntStream numbersFromOneToTen() {
return IntStream.rangeClosed(1, 10);
}
}
Using objects as test data
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertFalse;
class UserValidationTest {
@ParameterizedTest
@MethodSource("invalidUsers")
void shouldRejectInvalidUsers(User user) {
assertFalse(user.isValid());
}
static Stream<Arguments> invalidUsers() {
return Stream.of(
Arguments.of(new User("", "[email protected]")),
Arguments.of(new User("Alice", "")),
Arguments.of(new User(null, "[email protected]"))
);
}
static class User {
private final String name;
private final String email;
User(String name, String email) {
this.name = name;
this.email = email;
}
boolean isValid() {
return name != null && !name.isBlank()
&& email != null && !email.isBlank();
}
}
}
Referencing an external method source
You can also put test data providers in another class.
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
class MathTest {
@ParameterizedTest
@MethodSource("com.example.TestData#additionCases")
void shouldAddNumbers(int a, int b, int expected) {
assertEquals(expected, a + b);
}
}
package com.example;
import org.junit.jupiter.params.provider.Arguments;
import java.util.stream.Stream;
public class TestData {
static Stream<Arguments> additionCases() {
return Stream.of(
Arguments.of(1, 2, 3),
Arguments.of(10, 20, 30)
);
}
}
Depending on your setup, make the provider method public static if it is in a different package or class.
Common rules
For standard JUnit 5 usage:
- The test must use
@ParameterizedTest. - The provider method usually must be
static. - The provider method can return:
Stream<T>Stream<Arguments>Collection<T>Iterable<T>- arrays
- primitive streams like
IntStream,LongStream, orDoubleStream
- Use
Arguments.of(...)when passing multiple values. - The number and types of provided arguments must match the test method parameters.
Example with readable test names
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
class DiscountTest {
@ParameterizedTest(name = "{index}: price={0}, discount={1}, expected={2}")
@MethodSource("discountCases")
void shouldCalculateDiscount(double price, double discount, double expected) {
assertEquals(expected, price * (1 - discount));
}
static Stream<Arguments> discountCases() {
return Stream.of(
Arguments.of(100.0, 0.10, 90.0),
Arguments.of(200.0, 0.25, 150.0),
Arguments.of(50.0, 0.00, 50.0)
);
}
}
In short, use @MethodSource when you want flexible, reusable, or dynamically generated test data for parameterized tests.
