Parameterized tests allow you to run the same test multiple times with different inputs. This is particularly useful for testing functions that should behave the same way for a variety of inputs. In this section, we will cover how to create parameterized tests in JUnit.
Key Concepts
- Parameterized Tests: Tests that run multiple times with different sets of parameters.
- @ParameterizedTest: Annotation used to denote a parameterized test.
- @ValueSource: Annotation used to provide a single array of values to the parameterized test.
- @CsvSource: Annotation used to provide multiple sets of values in CSV format.
- @MethodSource: Annotation used to provide a method that returns a stream of arguments.
Step-by-Step Guide
- Adding Dependencies
First, ensure you have the necessary dependencies in your pom.xml (for Maven) or build.gradle (for Gradle) file.
Maven:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>Gradle:
- Creating a Simple Parameterized Test
Let's start with a simple example using @ValueSource.
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ParameterizedTestExample {
@ParameterizedTest
@ValueSource(strings = {"racecar", "radar", "level"})
void testPalindrome(String candidate) {
assertTrue(isPalindrome(candidate));
}
boolean isPalindrome(String str) {
return str.equals(new StringBuilder(str).reverse().toString());
}
}Explanation:
@ParameterizedTestindicates that the method is a parameterized test.@ValueSource(strings = {"racecar", "radar", "level"})provides the parameters for the test.- The
testPalindromemethod will run three times, once for each string in the@ValueSource.
- Using @CsvSource for Multiple Parameters
If you need to pass multiple parameters, you can use @CsvSource.
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CsvSourceExample {
@ParameterizedTest
@CsvSource({
"1, 1, 2",
"2, 3, 5",
"3, 5, 8"
})
void testAddition(int a, int b, int expected) {
assertEquals(expected, add(a, b));
}
int add(int a, int b) {
return a + b;
}
}Explanation:
@CsvSourceprovides multiple sets of parameters in CSV format.- The
testAdditionmethod will run three times with different sets of parameters.
- Using @MethodSource for Complex Parameters
For more complex scenarios, you can use @MethodSource to provide parameters from a method.
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MethodSourceExample {
@ParameterizedTest
@MethodSource("provideStringsForIsBlank")
void testIsBlank(String input, boolean expected) {
assertEquals(expected, isBlank(input));
}
static Stream<Arguments> provideStringsForIsBlank() {
return Stream.of(
Arguments.of(null, true),
Arguments.of("", true),
Arguments.of(" ", true),
Arguments.of("not blank", false)
);
}
boolean isBlank(String str) {
return str == null || str.trim().isEmpty();
}
}Explanation:
@MethodSource("provideStringsForIsBlank")specifies the method that provides the parameters.- The
provideStringsForIsBlankmethod returns a stream ofArguments. - The
testIsBlankmethod will run four times with different sets of parameters.
Practical Exercise
Exercise: Create a Parameterized Test for a Multiplication Function
- Create a method
multiply(int a, int b)that returns the product ofaandb. - Write a parameterized test using
@CsvSourceto test themultiplymethod with the following pairs of values:- (2, 3, 6)
- (4, 5, 20)
- (6, 7, 42)
Solution
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MultiplicationTest {
@ParameterizedTest
@CsvSource({
"2, 3, 6",
"4, 5, 20",
"6, 7, 42"
})
void testMultiply(int a, int b, int expected) {
assertEquals(expected, multiply(a, b));
}
int multiply(int a, int b) {
return a * b;
}
}Explanation:
- The
@CsvSourceannotation provides the parameters for the test. - The
testMultiplymethod will run three times with different sets of parameters.
Conclusion
In this section, we learned how to create parameterized tests in JUnit using @ValueSource, @CsvSource, and @MethodSource. Parameterized tests are a powerful feature that allows you to run the same test with different inputs, making your tests more comprehensive and reducing code duplication. In the next section, we will explore the @ParameterizedTest annotation in more detail.
JUnit Course
Module 1: Introduction to JUnit
Module 2: Basic JUnit Annotations
- Understanding @Test
- Using @Before and @After
- Using @BeforeClass and @AfterClass
- Ignoring Tests with @Ignore
Module 3: Assertions in JUnit
Module 4: Parameterized Tests
- Introduction to Parameterized Tests
- Creating Parameterized Tests
- Using @ParameterizedTest
- Custom Parameterized Tests
Module 5: Test Suites
Module 6: Mocking with JUnit
Module 7: Advanced JUnit Features
Module 8: Best Practices and Tips
- Writing Effective Tests
- Organizing Test Code
- Test-Driven Development (TDD)
- Continuous Integration with JUnit
