Bird
Raised Fist0
JUnittesting~10 mins

@MethodSource for factory methods in JUnit - Test Execution Trace

Choose your learning style10 modes available
Test Overview

This test uses JUnit's @MethodSource to supply multiple sets of data to a factory method. It verifies that the factory method creates objects correctly for each input.

Test Code - JUnit 5
JUnit
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;

class Product {
    private final String name;
    private final int price;

    Product(String name, int price) {
        this.name = name;
        this.price = price;
    }

    String getName() {
        return name;
    }

    int getPrice() {
        return price;
    }
}

public class ProductFactoryTest {

    static Stream<Product> productProvider() {
        return Stream.of(
            new Product("Book", 10),
            new Product("Pen", 2),
            new Product("Notebook", 5)
        );
    }

    @ParameterizedTest
    @MethodSource("productProvider")
    void testProductCreation(Product product) {
        assertNotNull(product);
        assertNotNull(product.getName());
        assertTrue(product.getPrice() > 0);
    }
}
Execution Trace - 6 Steps
StepActionSystem StateAssertionResult
1Test startsJUnit test runner initializes ProductFactoryTest class—PASS
2JUnit calls productProvider() method to get test data streamStream of 3 Product objects is created—PASS
3JUnit runs testProductCreation() with first Product("Book", 10)Product object with name 'Book' and price 10 is passed to testassertNotNull(product), assertNotNull(product.getName()), assertTrue(product.getPrice() > 0)PASS
4JUnit runs testProductCreation() with second Product("Pen", 2)Product object with name 'Pen' and price 2 is passed to testassertNotNull(product), assertNotNull(product.getName()), assertTrue(product.getPrice() > 0)PASS
5JUnit runs testProductCreation() with third Product("Notebook", 5)Product object with name 'Notebook' and price 5 is passed to testassertNotNull(product), assertNotNull(product.getName()), assertTrue(product.getPrice() > 0)PASS
6All parameterized tests completeAll 3 Product objects tested successfully—PASS
Failure Scenario
Failing Condition: productProvider() returns a Product with null name or price <= 0
Execution Trace Quiz - 3 Questions
Test your understanding
What does the @MethodSource annotation do in this test?
ARuns the test only once
BSupplies multiple Product objects as test inputs
CCreates a mock Product object
DSkips the test if no data is found
Key Result
Using @MethodSource with factory methods allows running the same test logic with different inputs, improving test coverage and reducing code duplication.

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