Inject Parameters into JUnit Jupiter Unit Tests
Last Updated :
23 Jul, 2025
JUnit 5 (also known as JUnit Jupiter) introduced several new features to enhance the process of writing unit tests. One of the key enhancements is the ability to inject parameters into test methods, simplifying the test setup and making the code more maintainable. Parameterized tests allow the test method to run multiple times with different arguments. In this article, we will explore how to inject parameters into JUnit Jupiter unit tests using various sources like value providers and arguments.
Injecting Parameters in JUnit 5
Parameterized tests in JUnit 5 (JUnit Jupiter) enable running the same test logic with different data sets, reducing redundancy and improving test coverage. By injecting parameters into test methods, we avoid the need for repetitive test code for different cases. The framework provides several annotations to facilitate parameter injection, making it flexible and powerful.
Why Use Parameterized Tests?
In traditional unit testing, we often need to test methods with multiple inputs, leading to repetitive test cases. Parameterized tests solve this problem by allowing a single test method to run multiple times with different arguments. The key benefits of using parameterized tests include:
- Code Reusability: A single test method can handle multiple inputs, avoiding the need to write separate methods for each test case.
- Test Coverage: Running the same test logic with various inputs ensures better test coverage.
- Readability: The code becomes cleaner and easier to understand, as we eliminate duplicate test logic.
How Parameterized Tests Work
JUnit 5 introduces the @ParameterizedTest annotation to mark the test method as the parameterized. This annotation can be used in the conjunction with various argument source annotations, which specify the source of the input data. The test method can be executed once for each set of the input data, with the parameters being automatically injected by the JUnit framework.
Here are the key elements used in parameterized tests:
- Test Method: The method where the actual test logic is written. This method will be executed multiple times with different parameters.
- Source Annotations: These annotations provides the input parameters. Some of the common ones include:
- @ValueSource: This annotation provides literal values such as the int, String, double, etc.
- @CsvSource: This annotation supplies multiple sets of the arguments in the comma-separated format.
- @EnumSource: This annotation passes values from the enum.
- @MethodSource: This annotation supplies parameters from a static method, allowing for more complex input preparation.
- @ArgumentsSource: This annotation uses the custom provider to generate parameters dynamically.
Key Annotations in JUnit 5 Parameter Injection
1. @ParameterizedTest
@ParameterizedTest annotation designates the method as a parameterized test. Unlike standard tests, this method will receive parameters injected by JUnit 5 based on the provided argument sources.
2. @ValueSource
The simplest way to inject values. It supports basic data types like int
, String
, double
, etc. You can provide a list of literal values that will be passed to the test method in each invocation.
Example:
@ParameterizedTest
@ValueSource(strings = {"apple", "banana", "orange"})
void testWithStringValue(String fruit) {
assertNotNull(fruit); // Asserts that the fruit is not null
}
3. @CsvSource
Allows injecting multiple arguments into the test method by providing a comma-separated list of values, useful for testing methods that take multiple parameters.
Example:
@ParameterizedTest
@CsvSource({
"apple, 5",
"banana, 6"
})
void testWithCsvSource(String fruit, int length) {
assertEquals(length, fruit.length()); // Asserts that the length matches the expected value
}
4. @MethodSource
Used when input parameters are complex or need to be generated programmatically. It refers to a static method that provides a stream of arguments.
Example:
@ParameterizedTest
@MethodSource("stringProvider")
void testWithMethodSource(String argument) {
assertTrue(argument.startsWith("a")); // Asserts that the argument starts with 'a'
}
static Stream<String> stringProvider() {
return Stream.of("apple", "avocado"); // Provides test arguments
}
5. @EnumSource
Ideal for testing with all or a subset of Enum constants. It injects the Enum values into the test method.
Example:
enum Season { WINTER, SPRING, SUMMER, FALL }
@ParameterizedTest
@EnumSource(Season.class)
void testWithEnumSource(Season season) {
assertNotNull(season); // Asserts that the season is not null
}
6. @ArgumentsSource
For advanced scenarios, it defines a custom arguments provider by implementing the ArgumentsProvider
interface, allowing full control over how arguments are generated.
Example:
static class CustomArgumentsProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(Arguments.of("apple", 5), Arguments.of("banana", 6)); // Provides custom test arguments
}
}
@ParameterizedTest
@ArgumentsSource(CustomArgumentsProvider.class)
void testWithCustomArguments(String fruit, int length) {
assertEquals(length, fruit.length()); // Asserts that the length matches the expected value
}
Implementation of Parameterized Tests in JUnit 5
This example project demonstrates how to inject the parameters into JUnit 5 unit tests.
Step 1: Create a New Maven Project
Create a new Maven project using IntelliJ IDEA with the following options:
- Name:
junit5-parameterized-tests
- Build System: Maven
Click on the Create button.
Project Structure
After project creation done successfully, the folder structure will look like the below image:
Step 2: Add Dependencies to pom.xml
Open the pom.xml
and add the JUnit 5 dependencies to the Maven project.
XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gfg</groupId>
<artifactId>junit5-parameterized-tests</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.11.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Maven Surefire plugin to run JUnit tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
</plugins>
</build>
</project>
Step 3: Create a Calculator Class
Create a simple Calculator
class that performs basic operations like addition, subtraction, multiplication, and division. This class serves as the subject of our unit tests.
Calculator.java:
Java
package com.gfg;
public class Calculator {
// Adds two integers and returns the result
public int add(int a, int b)
{
return a + b;
}
// Subtracts the second integer from the first and returns the result
public int subtract(int a, int b)
{
return a - b;
}
// Multiplies two integers and returns the result
public int multiply(int a, int b)
{
return a * b;
}
// Divides the first integer by the second and returns the result
// Throws an exception if the second integer is zero
public int divide(int a, int b)
{
if (b == 0) {
throw new IllegalArgumentException("Division by zero is not allowed");
}
return a / b;
}
}
Step 4: Main Class
Add a simple main class to use the Calculator
service directly. This class simulates a basic command-line application that performs arithmetic operations.
Main. java:
Java
package com.gfg;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator(); // Creates an instance of the Calculator class
Scanner scanner = new Scanner(System.in); // Scanner for user input
System.out.println("Welcome to the Calculator App");
System.out.println("Please choose an operation: add, subtract, multiply, divide");
String operation = scanner.nextLine(); // Reads the operation choice
System.out.println("Enter the first number: ");
int num1 = scanner.nextInt(); // Reads the first number
System.out.println("Enter the second number: ");
int num2 = scanner.nextInt(); // Reads the second number
int result = 0; // Variable to store the result
// Performs the chosen operation
switch (operation.toLowerCase()) {
case "add":
result = calculator.add(num1, num2);
break;
case "subtract":
result = calculator.subtract(num1, num2);
break;
case "multiply":
result = calculator.multiply(num1, num2);
break;
case "divide":
result = calculator.divide(num1, num2);
break;
default:
System.out.println("Invalid operation!"); // Error message for invalid operation
return;
}
System.out.println("The result is: " + result); // Outputs the result
}
}
Step 5: Create Parameterized Tests for Calculator
Create the CalculatorTest class, which will contain the tests for our Calculator class. This file will demonstrate the use of the @ParameterizedTest and various parameter sources such as the @ValueSource, @CsvSource, and @MethodSource.
CalculatorTest.java:
Java
package com.gfg;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.*;
class CalculatorTest {
private final Calculator calculator = new Calculator(); // Instance of the Calculator for testing
// Tests the add method with various inputs
@ParameterizedTest
@CsvSource({
"1, 2, 3", // 1 + 2 = 3
"5, 6, 11", // 5 + 6 = 11
"-1, 1, 0" // -1 + 1 = 0
})
void testAdd(int a, int b, int expected)
{
assertEquals(expected, calculator.add(a, b)); // Asserts that the result matches the expected value
}
// Tests the subtract method with various inputs
@ParameterizedTest
@CsvSource({
"5, 3, 2", // 5 - 3 = 2
"10, 4, 6", // 10 - 4 = 6
"-1, -1, 0" // -1 - -1 = 0
})
void testSubtract(int a, int b, int expected)
{
assertEquals(expected, calculator.subtract(a, b)); // Asserts that the result matches the expected value
}
// Tests the multiply method with various inputs
@ParameterizedTest
@ValueSource(ints = {2, 3, 5})
void testMultiply(int number) {
assertEquals(0, calculator.multiply(number, 0)); // Asserts that multiplying by 0 results in 0
}
// Tests the divide method with valid inputs
@ParameterizedTest
@CsvSource({
"6, 2, 3", // 6 / 2 = 3
"9, 3, 3", // 9 / 3 = 3
"0, 1, 0" // 0 / 1 = 0
})
void testDivide(int a, int b, int expected) {
assertEquals(expected, calculator.divide(a, b)); // Asserts that the result matches the expected value
}
// Tests the divide method for division by zero
@Test
void testDivideByZero() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
calculator.divide(10, 0); // This should throw an exception
});
assertEquals("Division by zero is not allowed", exception.getMessage()); // Asserts that the exception message is correct
}
}
Step 6: Run the Application
Once the project is completed, it will run and show the below output:
Step 7: Running the Tests
We can use the following command to run the tests:
mvn test
When we run the tests, we should see the following output:
This example project demonstrates how to implement the parameterized tests in the JUnit 5 using annotations like @ValueSource, @CsvSource, and @MethodSource. The ability to inject parameters makes the unit tests more flexible, reusable, and easier to maintain.
Similar Reads
Writing Templates for Test Cases Using JUnit 5 Writing consistent and reusable test case templates is essential for maintaining quality and ensuring uniformity in large-scale projects. Test case templates provide a structured approach for documenting and executing test scenarios, making it easier to identify issues, automate testing, and validat
7 min read
JUnit 5 - Eclipse Test Templates JUnit 5 simplifies the process of writing and executing test cases in Java applications. It offers enhanced support for modern Java features, increased extensibility, and a testing API that is more flexible and expressive. Test TemplatesA test template is a predefined format for writing test cases o
7 min read
Unit Testing in Spring Boot Project using Mockito and Junit Spring Boot is a Java-based framework built on top of Spring that simplifies application development with minimal configuration. Itâs ideal for creating production-ready applications quickly, thanks to features like embedded servers, auto-configuration and reduced boilerplate code.Mockito is an open
4 min read
JUnit 5 - @ParameterizedTest Parameterized tests in JUnit 5 provide the ability to run the same test multiple times with different inputs, helping to improve code coverage and catch edge cases that might otherwise go unnoticed By automating test execution with multiple sets of input data, parameterized tests simplify validation
4 min read
Unit Testing System.in for Input Handling in JUnit In Java applications, itâs common to read input from System.in for interactive console applications. Unit testing such methods can be challenging because they rely on user input. We can achieve this by redirecting System.in to a ByteArrayInputStream that contains the input we want to simulate. In th
6 min read
JUnit â Executing Tests with Maven Build JUnit is a widely-used testing framework for Java that allows developers to create and execute unit tests. When combined with Maven, the build automation tool, it becomes easy to automate the execution of these tests as part of the build lifecycle. In this article, we will explore how JUnit works wi
6 min read