Argument conversion in JUnit - Build an Automation Script
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.converter.ArgumentConversionException; import org.junit.jupiter.params.converter.ArgumentConverter; import org.junit.jupiter.params.converter.ConvertWith; import org.junit.jupiter.params.provider.ValueSource; class Temperature { private final double celsius; public Temperature(double celsius) { this.celsius = celsius; } public double getCelsius() { return celsius; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Temperature other = (Temperature) obj; return Double.compare(other.celsius, celsius) == 0; } @Override public int hashCode() { return Double.hashCode(celsius); } } class TemperatureConverter implements ArgumentConverter { @Override public Object convert(Object source, java.lang.reflect.Parameter context) throws ArgumentConversionException { if (!(source instanceof String)) { throw new ArgumentConversionException("Can only convert from String"); } String str = (String) source; try { // Assume input like "36.5C" - remove 'C' and parse double if (!str.endsWith("C")) { throw new ArgumentConversionException("String must end with 'C'"); } double value = Double.parseDouble(str.substring(0, str.length() - 1)); return new Temperature(value); } catch (NumberFormatException e) { throw new ArgumentConversionException("Invalid temperature format", e); } } } public class ArgumentConversionTest { @ParameterizedTest @ValueSource(strings = {"36.5C", "0C", "100C"}) void testTemperatureConversion(@ConvertWith(TemperatureConverter.class) Temperature temp) { Assertions.assertNotNull(temp); // Check that the celsius value matches expected values String input = temp.getCelsius() + "C"; Assertions.assertTrue(input.endsWith("C")); } }
This test uses JUnit 5's parameterized test feature with @ValueSource to provide string inputs representing temperatures.
The TemperatureConverter class implements ArgumentConverter to convert the input string (like "36.5C") into a Temperature object by parsing the numeric part.
The test method testTemperatureConversion uses @ConvertWith to apply this converter to the parameter. Inside the test, assertions check that the converted object is not null and that the value ends with 'C', confirming correct conversion.
This approach keeps the test clean and focused on verifying argument conversion works as expected.
Now add data-driven testing with 3 different temperature string inputs including edge cases like negative and zero values
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
