Bird
Raised Fist0
JUnittesting~8 mins

@ArgumentsSource with custom providers in JUnit - Framework Patterns

Choose your learning style10 modes available
Framework Mode - @ArgumentsSource with custom providers
Folder Structure
project-root/
├── src/
│   ├── main/
│   │   └── java/
│   │       └── com/example/app/          # Application source code
│   └── test/
│       └── java/
│           └── com/example/tests/        # Test classes
│               ├── providers/             # Custom ArgumentsProvider providers
│               │   └── CustomArgsProvider.java
│               ├── tests/                 # Parameterized test classes
│               │   └── SampleParameterizedTest.java
│               └── utils/                 # Test utilities and helpers
│                   └── TestUtils.java
└── build.gradle or pom.xml                 # Build and dependency management
    
Test Framework Layers
  • Test Classes: Contain parameterized tests using @ArgumentsSource annotation to inject test data.
  • Custom Arguments Providers: Implement ArgumentsProvider interface to supply test arguments programmatically.
  • Utilities: Helper methods for data preparation or common test logic.
  • Configuration: Manage environment settings, test parameters, and dependencies.
  • Build & Dependency Management: Use Gradle or Maven to manage JUnit 5 and other dependencies.
Configuration Patterns

Use pom.xml or build.gradle to declare JUnit 5 dependencies, including junit-jupiter-params for parameterized tests.

Example Gradle snippet:

plugins {
    id 'java'
}

dependencies {
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.0'
    testImplementation 'org.junit.jupiter:junit-jupiter-params:5.10.0'
}

test {
    useJUnitPlatform()
}
    

Environment-specific settings can be handled via system properties or profiles if needed.

Test Reporting and CI/CD Integration
  • JUnit 5 generates XML reports compatible with CI tools like Jenkins, GitHub Actions, or GitLab CI.
  • Use build tool plugins (e.g., maven-surefire-plugin or Gradle's test task) to produce reports.
  • Integrate with CI pipelines to run tests automatically on commits or pull requests.
  • Use IDE test runners for local feedback with clear pass/fail and stack traces.
Best Practices
  1. Separate Data Providers: Keep custom ArgumentsProvider classes in a dedicated package for clarity and reuse.
  2. Implement ArgumentsProvider Correctly: Override provideArguments method to return a Stream<Arguments> with valid test data.
  3. Use Descriptive Test Names: Use @ParameterizedTest(name = "{index} => input={0}, expected={1}") for readable test reports.
  4. Keep Tests Independent: Each test invocation should be isolated and not depend on others.
  5. Use Assertions Clearly: Assert expected outcomes with meaningful messages for easier debugging.
Self Check

Where in this folder structure would you add a new custom ArgumentsProvider for a Login feature test?

Key Result
Organize parameterized tests with custom ArgumentsProvider classes under a dedicated package, using JUnit 5's @ArgumentsSource for clean, reusable test data injection.

Practice

(1/5)
1. What is the main purpose of using @ArgumentsSource in JUnit tests?
easy
A. To mark a test method as disabled
B. To provide custom test data from a class implementing ArgumentsProvider
C. To specify the order of test execution
D. To inject mock objects into tests

Solution

  1. Step 1: Understand the role of @ArgumentsSource

    This annotation is used to supply custom arguments to parameterized tests by referencing a class that implements ArgumentsProvider.
  2. Step 2: Differentiate from other annotations

    Other options like disabling tests or ordering are handled by different annotations, not @ArgumentsSource.
  3. Final Answer:

    To provide custom test data from a class implementing ArgumentsProvider -> Option B
  4. Quick Check:

    @ArgumentsSource supplies custom test data [OK]
Hint: Remember: @ArgumentsSource links to custom data providers [OK]
Common Mistakes:
  • Confusing @ArgumentsSource with @Disabled
  • Thinking it controls test order
  • Assuming it injects mocks
2. Which of the following is the correct way to declare a custom ArgumentsProvider class for use with @ArgumentsSource?
easy
A. public class MyProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(1)); } }
B. public class MyProvider { public Stream<Arguments> provideArguments() { return Stream.of(Arguments.of(1)); } }
C. public class MyProvider implements ArgumentsSource { public Stream<Arguments> provideArguments() { return Stream.of(Arguments.of(1)); } }
D. public class MyProvider implements ArgumentsProvider { public List<Arguments> provideArguments() { return List.of(Arguments.of(1)); } }

Solution

  1. Step 1: Check interface implementation and method signature

    The class must implement ArgumentsProvider and override provideArguments(ExtensionContext) returning a Stream<Arguments>.
  2. Step 2: Validate return type and method parameters

    public class MyProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(1)); } } correctly implements the interface and method signature. public class MyProvider { public Stream<Arguments> provideArguments() { return Stream.of(Arguments.of(1)); } } misses the interface and method parameter. public class MyProvider implements ArgumentsSource { public Stream<Arguments> provideArguments() { return Stream.of(Arguments.of(1)); } } wrongly implements ArgumentsSource which is an annotation, not an interface. public class MyProvider implements ArgumentsProvider { public List<Arguments> provideArguments() { return List.of(Arguments.of(1)); } } returns a List instead of a Stream.
  3. Final Answer:

    public class MyProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(1)); } } -> Option A
  4. Quick Check:

    Implement ArgumentsProvider with correct method signature [OK]
Hint: Implement ArgumentsProvider with provideArguments(ExtensionContext) [OK]
Common Mistakes:
  • Forgetting to implement ArgumentsProvider
  • Wrong method signature or missing parameter
  • Returning List instead of Stream
  • Confusing ArgumentsSource annotation with interface
3. Given the following custom provider and test method, what will be the output when the test runs?
public class NumberProvider implements ArgumentsProvider {
    public Stream<Arguments> provideArguments(ExtensionContext context) {
        return Stream.of(Arguments.of(2), Arguments.of(4));
    }
}

@ParameterizedTest
@ArgumentsSource(NumberProvider.class)
void testIsEven(int number) {
    assertTrue(number % 2 == 0);
}
medium
A. Compilation error due to missing annotation
B. Test fails because 4 is not even
C. Both tests pass because 2 and 4 are even numbers
D. Test fails because 2 is not even

Solution

  1. Step 1: Analyze the provided arguments

    The provider returns two arguments: 2 and 4, both even numbers.
  2. Step 2: Check the assertion logic

    The test asserts that the number modulo 2 equals 0, which is true for both 2 and 4.
  3. Final Answer:

    Both tests pass because 2 and 4 are even numbers -> Option C
  4. Quick Check:

    2 % 2 == 0 and 4 % 2 == 0 [OK]
Hint: Check if all provided numbers satisfy the assertion condition [OK]
Common Mistakes:
  • Assuming 4 is odd
  • Ignoring the assertion logic
  • Confusing test failure with compilation error
4. Identify the error in the following custom ArgumentsProvider implementation:
public class StringProvider implements ArgumentsProvider {
    public List<Arguments> provideArguments(ExtensionContext context) {
        return List.of(Arguments.of("test"));
    }
}
medium
A. Method name should be getArguments instead of provideArguments
B. Class must implement ArgumentsSource instead of ArgumentsProvider
C. No error, code is correct
D. Method should return Stream<Arguments>, not List<Arguments>

Solution

  1. Step 1: Check the return type of provideArguments

    The ArgumentsProvider interface requires provideArguments to return a Stream<Arguments>, but the code returns a List<Arguments>.
  2. Step 2: Validate interface and method name

    The class correctly implements ArgumentsProvider and the method name is correct.
  3. Final Answer:

    Method should return Stream<Arguments>, not List<Arguments> -> Option D
  4. Quick Check:

    Return type must be Stream<Arguments> [OK]
Hint: Remember: provideArguments returns Stream, not List [OK]
Common Mistakes:
  • Returning List instead of Stream
  • Confusing interface with annotation
  • Wrong method name
5. You want to test a method that accepts a pair of integers and returns their sum. You decide to use @ArgumentsSource with a custom provider that supplies pairs. Which of the following ArgumentsProvider implementations correctly provides pairs of integers for the test?
hard
A. public class PairProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(1, 2), Arguments.of(3, 4)); } }
B. public class PairProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(new int[]{1, 2}), Arguments.of(new int[]{3, 4})); } }
C. public class PairProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(List.of(1, 2)), Arguments.of(List.of(3, 4))); } }
D. public class PairProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(1), Arguments.of(2), Arguments.of(3), Arguments.of(4)); } }

Solution

  1. Step 1: Understand the test method parameters

    The test method expects two integer parameters per test invocation, so each Arguments must supply two integers.
  2. Step 2: Evaluate each provider's argument format

    public class PairProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(1, 2), Arguments.of(3, 4)); } } correctly provides pairs of integers as separate arguments. public class PairProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(new int[]{1, 2}), Arguments.of(new int[]{3, 4})); } } provides arrays which may not match the method signature expecting two int parameters. public class PairProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(List.of(1, 2)), Arguments.of(List.of(3, 4))); } } provides lists which also do not match two int parameters directly. public class PairProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(1), Arguments.of(2), Arguments.of(3), Arguments.of(4)); } } provides single integers, not pairs.
  3. Final Answer:

    public class PairProvider implements ArgumentsProvider { public Stream<Arguments> provideArguments(ExtensionContext context) { return Stream.of(Arguments.of(1, 2), Arguments.of(3, 4)); } } -> Option A
  4. Quick Check:

    Each Arguments.of() must match method parameters [OK]
Hint: Match Arguments.of() parameters count to test method parameters [OK]
Common Mistakes:
  • Passing arrays or lists instead of separate parameters
  • Providing single arguments when pairs are needed
  • Not matching argument count to method parameters
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