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:
@ParameterizedTest
indicates that the method is a parameterized test.@ValueSource(strings = {"racecar", "radar", "level"})
provides the parameters for the test.- The
testPalindrome
method 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:
@CsvSource
provides multiple sets of parameters in CSV format.- The
testAddition
method 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
provideStringsForIsBlank
method returns a stream ofArguments
. - The
testIsBlank
method 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 ofa
andb
. - Write a parameterized test using
@CsvSource
to test themultiply
method 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
@CsvSource
annotation provides the parameters for the test. - The
testMultiply
method 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