Bird
Raised Fist0
JUnittesting~8 mins

@MethodSource for factory methods in JUnit - Framework Patterns

Choose your learning style10 modes available
Framework Mode - @MethodSource for factory methods
Folder Structure
project-root/
├── src/
│   ├── main/
│   │   └── java/
│   │       └── com/example/app/
│   │           └── (application code)
│   └── test/
│       └── java/
│           └── com/example/app/
│               ├── tests/
│               │   └── ExampleParameterizedTest.java
│               ├── factories/
│               │   └── TestDataFactory.java
│               └── utils/
│                   └── TestUtils.java
└── build.gradle (or pom.xml)
    
Test Framework Layers
  • Test Classes: Contain test methods using @ParameterizedTest and @MethodSource to get test data.
  • Factory Methods: Static methods in factory classes that provide streams or collections of arguments for parameterized tests.
  • Utilities: Helper methods for common test data creation or transformations.
  • Configuration: Setup for test environment, e.g., test profiles or system properties.
Configuration Patterns

Use @MethodSource to reference static factory methods by name. Factory methods should be public static and return Stream<Arguments> or compatible types.

Example factory method signature:

public static Stream<Arguments> provideTestData() { ... }

Manage environment-specific data by using system properties or environment variables inside factory methods if needed.

Keep test data separate from test logic by placing factory methods in dedicated classes (e.g., factories/TestDataFactory.java).

Test Reporting and CI/CD Integration
  • JUnit 5 integrates with build tools like Maven or Gradle to generate test reports in XML or HTML formats.
  • CI/CD pipelines (e.g., Jenkins, GitHub Actions) run tests automatically and publish reports.
  • Parameterized tests with @MethodSource show each data set as a separate test case in reports, making it easy to identify failures.
  • Use descriptive names with @DisplayName or name attribute in @ParameterizedTest to improve report readability.
Best Practices
  • Separate Test Data: Keep factory methods in dedicated classes to keep tests clean and maintainable.
  • Use Streams: Return Stream<Arguments> for flexibility and lazy evaluation of test data.
  • Descriptive Test Names: Use @DisplayName or parameterized test name patterns to clarify test cases.
  • Reuse Factory Methods: Share common test data across multiple tests to avoid duplication.
  • Keep Factory Methods Static: This is required by JUnit 5 for @MethodSource to work properly.
Self Check

Where in this folder structure would you add a new factory method that provides test data for a login feature?

Key Result
Use static factory methods in dedicated classes to supply test data via @MethodSource for clean, reusable parameterized tests.

Practice

(1/5)
1. What is the main purpose of using @MethodSource in JUnit tests?
easy
A. To skip a test method during execution
B. To create a new test class automatically
C. To provide multiple sets of data to a single test method
D. To run tests in parallel threads

Solution

  1. 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.
  2. 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.
  3. Final Answer:

    To provide multiple sets of data to a single test method -> Option C
  4. Quick Check:

    @MethodSource = multiple data sets [OK]
Hint: Remember: @MethodSource feeds data to one test method [OK]
Common Mistakes:
  • Thinking @MethodSource creates tests automatically
  • Confusing @MethodSource with test skipping annotations
  • Assuming @MethodSource controls test threading
2. Which of the following is the correct way to declare a factory method for @MethodSource in JUnit 5?
easy
A. public static Stream<Arguments> provideData()
B. private Stream<Arguments> provideData()
C. public Stream<Arguments> provideData()
D. static Stream<Arguments> provideData()

Solution

  1. Step 1: Recall factory method requirements

    Factory methods used with @MethodSource must be static and public to be accessible by the test framework.
  2. 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.
  3. Final Answer:

    public static Stream<Arguments> provideData() -> Option A
  4. Quick Check:

    Factory method = public static [OK]
Hint: Factory methods must be public and static [OK]
Common Mistakes:
  • Omitting static keyword
  • Making the method private
  • Using wrong return type
3. Given the following code snippet, what will be the output when the test runs?
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)
        );
    }
}
medium
A. Test fails on the last data set because 3 + 5 != 9
B. All tests pass successfully
C. Compilation error due to missing imports
D. Runtime error because dataProvider is not static

Solution

  1. 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.
  2. Step 2: Identify test result

    The third test case fails because the expected value is incorrect.
  3. Final Answer:

    Test fails on the last data set because 3 + 5 != 9 -> Option A
  4. Quick Check:

    3+5=8 ≠ 9, test fails [OK]
Hint: Check each input-output pair carefully [OK]
Common Mistakes:
  • Assuming all tests pass without checking values
  • Ignoring the static keyword correctness
  • Confusing compilation and runtime errors
4. Identify the error in the following JUnit test using @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)
        );
    }
}
medium
A. The test method must return a value
B. The factory method 'numbers' must be static
C. The @MethodSource annotation should specify a class name
D. The Stream should contain Arguments objects, not Integers

Solution

  1. Step 1: Check factory method signature

    The method 'numbers' is not static, but factory methods for @MethodSource must be static to be accessible.
  2. Step 2: Suggest fix

    Make the 'numbers' method static by adding the static keyword.
  3. Final Answer:

    The factory method 'numbers' must be static -> Option B
  4. Quick Check:

    Factory method must be static [OK]
Hint: Factory methods must be static to be found [OK]
Common Mistakes:
  • Forgetting static keyword on factory method
  • Thinking test methods must return values
  • Assuming @MethodSource needs class name always
5. You want to test a method that calculates discounts for different customer types using @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?
hard
A. Exclude unknown customer types from the factory method to avoid test failure
B. Use a separate test method without @MethodSource for unknown types
C. Throw an exception in the factory method for unknown customer types
D. Include an Arguments entry with unknown customer type and expected discount 0 in the factory method

Solution

  1. Step 1: Understand test coverage needs

    To test all cases including unknown customer types, the factory method should provide data for them explicitly.
  2. 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.
  3. Final Answer:

    Include an Arguments entry with unknown customer type and expected discount 0 in the factory method -> Option D
  4. Quick Check:

    Test all cases by including zero discount data [OK]
Hint: Always include edge cases in factory data [OK]
Common Mistakes:
  • Skipping edge cases in factory method
  • Expecting exceptions instead of valid results
  • Splitting tests unnecessarily
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard