Argument conversion helps JUnit tests accept different types of inputs easily. It changes input data into the right form for the test.
Argument conversion in JUnit
@ParameterizedTest
@ValueSource(strings = {"input1", "input2"})
void testMethod(@ConvertWith(MyConverter.class) MyType arg) {
// test code
}
// Converter class example
class MyConverter extends SimpleArgumentConverter {
@Override
protected Object convert(Object source, Class<?> targetType) {
// conversion logic
return null; // placeholder return
}
}The @ConvertWith annotation tells JUnit to use a custom converter for the argument.
The converter class must extend SimpleArgumentConverter and override the convert method.
@ParameterizedTest
@ValueSource(strings = {"123", "456"})
void testWithInteger(@ConvertWith(IntegerConverter.class) Integer number) {
assertTrue(number > 0);
}
class IntegerConverter extends SimpleArgumentConverter {
@Override
protected Object convert(Object source, Class<?> targetType) {
return Integer.parseInt(source.toString());
}
}@ParameterizedTest
@ValueSource(strings = {"John,25", "Jane,30"})
void testWithPerson(@ConvertWith(PersonConverter.class) Person person) {
assertNotNull(person.getName());
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
}
class PersonConverter extends SimpleArgumentConverter {
@Override
protected Object convert(Object source, Class<?> targetType) {
String[] parts = source.toString().split(",");
return new Person(parts[0], Integer.parseInt(parts[1]));
}
}This test converts string inputs "true" or "false" into Boolean objects using a custom converter. It checks that the conversion is not null and prints the converted value.
import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.converter.SimpleArgumentConverter; import org.junit.jupiter.params.converter.ConvertWith; import org.junit.jupiter.params.provider.ValueSource; class ArgumentConversionTest { static class BooleanConverter extends SimpleArgumentConverter { @Override protected Object convert(Object source, Class<?> targetType) { return Boolean.parseBoolean(source.toString()); } } @ParameterizedTest @ValueSource(strings = {"true", "false", "true"}) void testBooleanConversion(@ConvertWith(BooleanConverter.class) Boolean flag) { assertNotNull(flag); System.out.println("Converted value: " + flag); } }
Always ensure your converter handles invalid input gracefully to avoid test failures.
Use argument conversion to keep your test methods simple and focused on testing logic.
Argument conversion changes input data into the needed type for tests.
Use @ConvertWith with a converter class extending SimpleArgumentConverter.
This helps run parameterized tests with complex or custom data types.
Practice
@ConvertWith in JUnit parameterized tests?Solution
Step 1: Understand the role of argument conversion
Argument conversion changes input data into the type needed by the test method parameters.Step 2: Identify the purpose of
The@ConvertWith@ConvertWithannotation tells JUnit which converter class to use to transform the input argument.Final Answer:
To convert input arguments to the required test method parameter types -> Option CQuick Check:
Argument conversion = convert input arguments [OK]
- Thinking @ConvertWith skips tests
- Confusing conversion with logging
- Assuming it generates test data
Solution
Step 1: Recall JUnit's recommended base class for converters
JUnit providesSimpleArgumentConverteras a base class to extend for custom converters.Step 2: Match the correct class declaration
The correct syntax is to extendSimpleArgumentConverter, not implement interfaces or extend unknown classes.Final Answer:
public class MyConverter extends SimpleArgumentConverter { ... } -> Option AQuick Check:
Extend SimpleArgumentConverter = correct converter class [OK]
- Implementing ArgumentConverter interface directly
- Extending non-existent base classes
- Using wrong interface names
@ParameterizedTest
@ValueSource(strings = {"42"})
void testWithConversion(@ConvertWith(MyConverter.class) Integer number) {
System.out.println(number + 8);
}
public class MyConverter extends SimpleArgumentConverter {
@Override
protected Object convert(Object source, Class targetType) {
return Integer.parseInt(source.toString());
}
}Solution
Step 1: Understand the conversion process
The string "42" is converted to Integer 42 by MyConverter using Integer.parseInt.Step 2: Calculate the printed output
The test method adds 8 to the converted Integer 42, resulting in 50 printed.Final Answer:
50 -> Option AQuick Check:
42 + 8 = 50 [OK]
- Assuming no conversion happens
- Expecting string concatenation instead of addition
- Thinking code causes errors
public class MyConverter extends SimpleArgumentConverter {
@Override
protected Object convert(Object source, Class targetType) {
if (targetType != Integer.class) {
throw new IllegalArgumentException("Conversion only supports Integer");
}
return source;
}
}Solution
Step 1: Analyze the convert method's return value
The method returns source directly, which is a String, not converted to Integer.Step 2: Identify the missing conversion
It should parse the source string to Integer before returning, e.g., Integer.parseInt(source.toString()).Final Answer:
The source is returned without converting to Integer -> Option BQuick Check:
Return value must be converted type [OK]
- Returning source without conversion
- Using != instead of equals() for class check (less critical)
- Confusing return type requirements
"John,25,true" and converts it into a custom Person object with fields name (String), age (int), and active (boolean). Which approach correctly uses argument conversion in JUnit?Solution
Step 1: Understand the need for custom conversion
The input is a single CSV string that must be converted into a Person object before the test runs.Step 2: Identify the correct use of @ConvertWith
Creating a converter extending SimpleArgumentConverter that parses the CSV and returns a Person object, then annotating the test parameter with @ConvertWith, is the proper approach.Final Answer:
Create a converter extending SimpleArgumentConverter that splits the CSV and constructs Person; annotate parameter with @ConvertWith using this converter -> Option DQuick Check:
Custom converter + @ConvertWith = correct approach [OK]
- Parsing CSV inside test method instead of converter
- Using wrong annotation like @ArgumentsSource
- Passing multiple parameters without conversion
Ready to prove it?
Pass the test and this pattern moves unknown
