What if you could write one method to power hundreds of tests without repeating yourself?
Why @MethodSource for factory methods in JUnit? - Purpose & Use Cases
Imagine you have many test cases that need different sets of data. You write each test by hand, copying and pasting data over and over. It feels like filling out the same form again and again without any help.
Manually writing each test with repeated data is slow and boring. It's easy to make mistakes like typos or forgetting to update one test. When data changes, you must fix every test separately, which wastes time and causes errors.
@MethodSource lets you create one method that makes all the test data for you. Your tests just ask for the data from this method. This means less copying, fewer mistakes, and easy updates in one place.
void test1() { assertEquals(2, add(1,1)); }
void test2() { assertEquals(3, add(1,2)); }@ParameterizedTest @MethodSource("dataProvider") void testAdd(int a, int b, int expected) { assertEquals(expected, add(a,b)); } static Stream<Arguments> dataProvider() { return Stream.of(Arguments.of(1,1,2), Arguments.of(1,2,3)); }
You can run many tests easily with different data sets, all managed cleanly in one place.
Testing a calculator app with many input pairs and expected results, without writing separate tests for each pair.
Manual test data copying is slow and error-prone.
@MethodSource centralizes test data creation.
Tests become cleaner, easier to maintain, and scalable.
Practice
@MethodSource in JUnit tests?Solution
Step 1: Understand the role of @MethodSource
@MethodSource is used to supply multiple data sets to a single test method, allowing it to run multiple times with different inputs.Step 2: Compare options with this role
Options B, C, and D describe unrelated features. Only To provide multiple sets of data to a single test method correctly describes the purpose of @MethodSource.Final Answer:
To provide multiple sets of data to a single test method -> Option CQuick Check:
@MethodSource = multiple data sets [OK]
- Thinking @MethodSource creates tests automatically
- Confusing @MethodSource with test skipping annotations
- Assuming @MethodSource controls test threading
@MethodSource in JUnit 5?Solution
Step 1: Recall factory method requirements
Factory methods used with @MethodSource must be static and public to be accessible by the test framework.Step 2: Check each option
public static Stream<Arguments> provideData() is public and static, matching requirements. private Stream<Arguments> provideData() is private, so inaccessible. public Stream<Arguments> provideData() is public but not static. static Stream<Arguments> provideData() is static but missing public modifier.Final Answer:
public static Stream<Arguments> provideData() -> Option AQuick Check:
Factory method = public static [OK]
- Omitting static keyword
- Making the method private
- Using wrong return type
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.Arguments;
import java.util.stream.Stream;
public class CalculatorTest {
@ParameterizedTest
@MethodSource("dataProvider")
void testAdd(int a, int b, int expected) {
assertEquals(expected, a + b);
}
static Stream<Arguments> dataProvider() {
return Stream.of(
Arguments.of(1, 2, 3),
Arguments.of(2, 3, 5),
Arguments.of(3, 5, 9)
);
}
}Solution
Step 1: Check each data set against the assertion
First: 1 + 2 = 3 (matches expected 3), second: 2 + 3 = 5 (matches expected 5), third: 3 + 5 = 8 but expected is 9.Step 2: Identify test result
The third test case fails because the expected value is incorrect.Final Answer:
Test fails on the last data set because 3 + 5 != 9 -> Option AQuick Check:
3+5=8 ≠ 9, test fails [OK]
- Assuming all tests pass without checking values
- Ignoring the static keyword correctness
- Confusing compilation and runtime errors
@MethodSource and suggest a fix:import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.Arguments;
import java.util.stream.Stream;
public class SampleTest {
@ParameterizedTest
@MethodSource("numbers")
void testIsPositive(int number) {
assertTrue(number > 0);
}
Stream<Arguments> numbers() {
return Stream.of(
Arguments.of(1),
Arguments.of(2),
Arguments.of(3)
);
}
}Solution
Step 1: Check factory method signature
The method 'numbers' is not static, but factory methods for @MethodSource must be static to be accessible.Step 2: Suggest fix
Make the 'numbers' method static by adding the static keyword.Final Answer:
The factory method 'numbers' must be static -> Option BQuick Check:
Factory method must be static [OK]
- Forgetting static keyword on factory method
- Thinking test methods must return values
- Assuming @MethodSource needs class name always
@MethodSource. The factory method returns a Stream<Arguments> with customer type and expected discount. Which approach correctly handles a case where the discount is zero for unknown customer types without failing the test?Solution
Step 1: Understand test coverage needs
To test all cases including unknown customer types, the factory method should provide data for them explicitly.Step 2: Choose approach that includes zero discount case
Including an Arguments entry with unknown type and expected discount 0 ensures the test runs and verifies correct behavior without failure.Final Answer:
Include an Arguments entry with unknown customer type and expected discount 0 in the factory method -> Option DQuick Check:
Test all cases by including zero discount data [OK]
- Skipping edge cases in factory method
- Expecting exceptions instead of valid results
- Splitting tests unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
