ParameterResolver extension in JUnit - Build an Automation Script
import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.ParameterContext; import org.junit.jupiter.api.extension.ParameterResolver; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; // Custom object to be injected class CustomObject { private final String value; public CustomObject(String value) { this.value = value; } public String getValue() { return value; } } // ParameterResolver implementation class CustomObjectParameterResolver implements ParameterResolver { @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { return parameterContext.getParameter().getType() == CustomObject.class; } @Override public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) { return new CustomObject("InjectedValue"); } } @ExtendWith(CustomObjectParameterResolver.class) public class CustomObjectParameterResolverTest { @Test void testInjectedCustomObject(CustomObject customObject) { assertNotNull(customObject, "CustomObject should be injected and not null"); assertEquals("InjectedValue", customObject.getValue(), "CustomObject value should match the injected value"); } }
The code defines a CustomObject class with a simple string property.
The CustomObjectParameterResolver class implements JUnit 5's ParameterResolver interface. It overrides supportsParameter to check if the parameter type is CustomObject. It overrides resolveParameter to return a new CustomObject instance with a fixed value.
The test class CustomObjectParameterResolverTest is annotated with @ExtendWith to register the resolver. The test method testInjectedCustomObject accepts a CustomObject parameter, which JUnit injects automatically using the resolver.
Assertions check that the injected object is not null and that its value matches the expected string. This confirms the ParameterResolver works correctly.
Now add data-driven testing by injecting different CustomObject instances with different values for three test runs
Practice
ParameterResolver in JUnit 5?Solution
Step 1: Understand ParameterResolver role
A ParameterResolver is designed to supply values to parameters of test methods automatically, so tests don't need manual setup for those parameters.Step 2: Compare with other options
Options A, C, and D relate to other testing features but not to parameter injection.Final Answer:
To automatically provide values for test method parameters -> Option DQuick Check:
ParameterResolver = automatic parameter injection [OK]
- Confusing ParameterResolver with test ordering
- Thinking it creates mocks automatically
- Assuming it generates reports
ParameterResolver in JUnit 5?Solution
Step 1: Recall ParameterResolver interface methods
The ParameterResolver interface requires implementingsupportsParameterto check if a parameter is supported, andresolveParameterto provide the value.Step 2: Eliminate incorrect method pairs
Options A, B, and C list methods unrelated to ParameterResolver interface.Final Answer:
supportsParameter and resolveParameter -> Option AQuick Check:
ParameterResolver methods = supportsParameter + resolveParameter [OK]
- Confusing lifecycle methods with resolver methods
- Using incorrect method names
- Assuming initialization methods are required
class MyResolver implements ParameterResolver {
public boolean supportsParameter(ParameterContext pc, ExtensionContext ec) {
return pc.getParameter().getType() == String.class;
}
public Object resolveParameter(ParameterContext pc, ExtensionContext ec) {
return "InjectedValue";
}
}
@ExtendWith(MyResolver.class)
class TestClass {
@Test
void testMethod(String param) {
System.out.println(param);
}
}Solution
Step 1: Analyze supportsParameter method
It returns true only if the parameter type is String, so the test method's String param is supported.Step 2: Analyze resolveParameter method
It returns the string "InjectedValue", so this value will be injected into the test method parameter.Final Answer:
InjectedValue -> Option BQuick Check:
Parameter injection prints InjectedValue [OK]
- Assuming parameter is null if not supported
- Expecting compilation error due to interface methods
- Thinking test fails without explicit parameter value
class FaultyResolver implements ParameterResolver {
public boolean supportsParameter(ParameterContext pc, ExtensionContext ec) {
return pc.getParameter().getType() == Integer.class;
}
public Object resolveParameter(ParameterContext pc, ExtensionContext ec) {
return 42;
}
}
@ExtendWith(FaultyResolver.class)
class TestClass {
@Test
void testMethod(int param) {
System.out.println(param);
}
}Solution
Step 1: Check parameter type in supportsParameter
The test method parameter is primitiveint, but supportsParameter checks forInteger.class, which is the wrapper class. This causes supportsParameter to return false.Step 2: Understand consequence of mismatch
Because supportsParameter returns false, resolveParameter is never called, so the parameter is not injected, causing test failure or default value usage.Final Answer:
supportsParameter checks for Integer.class but parameter is primitive int -> Option CQuick Check:
Primitive vs wrapper mismatch breaks supportsParameter [OK]
- Ignoring difference between int and Integer
- Assuming @Override annotations are mandatory
- Thinking resolveParameter type must differ
String. Which implementation correctly achieves this and ensures a new UUID is generated for each test invocation?Solution
Step 1: Understand requirement for unique UUID per test
Each test invocation should get a new UUID string, so the UUID must be generated fresh every timeresolveParameteris called.Step 2: Evaluate options for UUID generation
InresolveParameter, returnUUID.randomUUID().toString()without caching generates a new UUID string on each call, fulfilling the requirement. Options B, C, and D cache or fix the UUID, so they do not produce unique values per test.Final Answer:
In resolveParameter, return UUID.randomUUID().toString() without caching -> Option AQuick Check:
Generate UUID fresh in resolveParameter for uniqueness [OK]
- Caching UUID and returning same value every time
- Generating UUID once in constructor
- Returning fixed string instead of UUID
Ready to prove it?
Pass the test and this pattern moves unknown
