In this section, we will explore the @ParameterizedTest
annotation in JUnit, which allows us to run the same test multiple times with different parameters. This is particularly useful for testing methods with a variety of inputs and expected outputs.
Key Concepts
- Parameterized Tests: Tests that run multiple times with different sets of parameters.
- @ParameterizedTest Annotation: Marks a method as a parameterized test.
- Source Annotations: Annotations like
@ValueSource
,@CsvSource
, and@MethodSource
that provide the parameters for the test.
Setting Up a Parameterized Test
Step-by-Step Guide
- Add JUnit 5 Dependency: Ensure you have JUnit 5 in your project dependencies.
- Create a Test Class: Define a class where you will write your parameterized tests.
- Use @ParameterizedTest: Annotate your test method with
@ParameterizedTest
. - Provide Parameters: Use source annotations to provide the parameters for the test.
Example
Let's create a simple parameterized test to check if a number is even.
Step 1: Add JUnit 5 Dependency
Ensure your pom.xml
(for Maven) or build.gradle
(for Gradle) includes JUnit 5.
Maven:
<dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.8.1</version> <scope>test</scope> </dependency>
Gradle:
Step 2: Create a Test Class
Create a new class for your tests.
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.assertTrue; public class NumberTest { @ParameterizedTest @ValueSource(ints = {2, 4, 6, 8, 10}) void testIsEven(int number) { assertTrue(isEven(number)); } boolean isEven(int number) { return number % 2 == 0; } }
Explanation
- @ParameterizedTest: Marks the
testIsEven
method as a parameterized test. - @ValueSource: Provides the parameters for the test. In this case, it provides an array of integers.
- assertTrue: Asserts that the condition is true. Here, it checks if the number is even.
Using Different Source Annotations
@CsvSource
Use @CsvSource
to provide multiple parameters.
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import static org.junit.jupiter.api.Assertions.assertEquals; public class MathTest { @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. Each set is a comma-separated string.
- assertEquals: Asserts that the expected value is equal to the actual value.
@MethodSource
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.assertTrue; public class StringTest { @ParameterizedTest @MethodSource("stringProvider") void testIsNotEmpty(String str) { assertTrue(str != null && !str.isEmpty()); } static Stream<String> stringProvider() { return Stream.of("apple", "banana", "cherry"); } }
Explanation
- @MethodSource: Specifies a method that provides the parameters. The method must return a
Stream
,Iterable
,Iterator
, or array. - assertTrue: Asserts that the string is not null and not empty.
Practical Exercise
Exercise
Create a parameterized test to check if a string is a palindrome.
- Create a new test class
PalindromeTest
. - Write a method
isPalindrome
that checks if a string is a palindrome. - Use
@ParameterizedTest
and@ValueSource
to test the method with different strings.
Solution
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.assertTrue; public class PalindromeTest { @ParameterizedTest @ValueSource(strings = {"madam", "racecar", "radar"}) void testIsPalindrome(String str) { assertTrue(isPalindrome(str)); } boolean isPalindrome(String str) { return str.equals(new StringBuilder(str).reverse().toString()); } }
Explanation
- @ValueSource: Provides an array of strings to test.
- isPalindrome: Checks if the string is equal to its reverse.
Common Mistakes and Tips
- Incorrect Parameter Types: Ensure the parameter types in the test method match those provided by the source annotation.
- Null Values: Handle null values appropriately in your tests.
- Complex Parameters: For complex parameters, consider using
@MethodSource
for better readability and maintainability.
Conclusion
In this section, we learned how to use the @ParameterizedTest
annotation in JUnit to run tests with different parameters. We explored various source annotations like @ValueSource
, @CsvSource
, and @MethodSource
to provide parameters. By using parameterized tests, we can write more comprehensive and efficient test cases, ensuring our code is robust and reliable.
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