@MethodSource for factory methods in JUnit - Build an Automation Script
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 { static Stream<Arguments> provideAddInputs() { return Stream.of( Arguments.of(1, 2, 3), Arguments.of(5, 7, 12), Arguments.of(-1, 1, 0) ); } @ParameterizedTest @MethodSource("provideAddInputs") void testAdd(int a, int b, int expectedSum) { Calculator calculator = new Calculator(); int result = calculator.add(a, b); assertEquals(expectedSum, result, () -> "Sum of " + a + " and " + b + " should be " + expectedSum); } } class Calculator { int add(int x, int y) { return x + y; } }
The static method provideAddInputs is the factory method that returns a Stream<Arguments>. Each Arguments.of() call provides one set of parameters for the test.
The test method testAdd is annotated with @ParameterizedTest and @MethodSource referencing the factory method by name. It accepts parameters matching the factory method's arguments.
Inside the test, we create a Calculator instance and call the add method with the parameters. Then we assert the result equals the expected sum.
This setup runs the test three times, once per data set, verifying the addition logic for different inputs.
Now add data-driven testing with 3 different inputs for a subtraction method using @MethodSource
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
