Question
Is it possible to create a single parameterized test class in JUnit that covers multiple methods like Add() and Subtract() without duplicating test code?
@RunWith(Parameterized.class)
public class CalculatorTest {
@Parameter
public int input1;
@Parameter
public int input2;
@Parameter
public int expectedAddResult;
@Parameter
public int expectedSubtractResult;
@Parameters(name = "Test {index}: add({0}, {1}) = {2}, subtract({0}, {1}) = {3}")
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 1, 2, 3, -1 },
{ 3, 5, 8, -2 },
{ 10, 2, 12, 8 },
});
}
@Test
public void testAdd() {
Calculator calculator = new Calculator();
assertEquals(expectedAddResult, calculator.Add(input1, input2));
}
@Test
public void testSubtract() {
Calculator calculator = new Calculator();
assertEquals(expectedSubtractResult, calculator.Subtract(input1, input2));
}
}
Answer
In JUnit, you can consolidate multiple parameter sets for different methods within a single test class. This is achieved through the use of the Parameterized runner, which allows you to define different sets of input and expected results for multiple test methods, greatly reducing code duplication and improving maintainability.
@RunWith(Parameterized.class)
public class CalculatorTest {
// Class variables for parameters
@Parameter
public int input1;
@Parameter
public int input2;
@Parameter
public int expectedAddResult;
@Parameter
public int expectedSubtractResult;
// Method providing test parameters
@Parameters(name = "Test {index}: add({0}, {1}) = {2}, subtract({0}, {1}) = {3}")
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 1, 2, 3, -1 },
{ 3, 5, 8, -2 },
{ 10, 2, 12, 8 },
});
}
// Test method for addition
@Test
public void testAdd() {
Calculator calculator = new Calculator();
assertEquals(expectedAddResult, calculator.Add(input1, input2));
}
// Test method for subtraction
@Test
public void testSubtract() {
Calculator calculator = new Calculator();
assertEquals(expectedSubtractResult, calculator.Subtract(input1, input2));
}
}
Causes
- Repetitive code across multiple test classes for similar functionalities.
- Lack of knowledge of JUnit's Parameterized tests capabilities.
Solutions
- Use the JUnit `@RunWith(Parameterized.class)` annotation to create a parameterized class.
- Define a static method annotated with `@Parameters` that returns all sets of parameters required for your tests.
- For each method under test (e.g., Add and Subtract), use instance variables to store inputs and expected outputs.
Common Mistakes
Mistake: Not initializing test method correctly for different operations (i.e., not using separate variables for each method).
Solution: Ensure you map parameters distinctly for each method you are testing.
Mistake: Forgetting to specify which method uses which parameter set in the @Parameters method.
Solution: Clearly document in the @Parameters method what each set of inputs corresponds to for readability.
Helpers
- JUnit parameterized test
- Combine parameter sets in JUnit
- Multiple methods in JUnit test class
- JUnit add and subtract tests
- Optimal JUnit test structuring