Parameterized tests
Now we are going to look into another type of test method, which is parameterized test. As the name implies this type is about passing parameters to the test methods. This might look similar to repeated tests that we discussed in the tutorial JUnit 5 - Repeated & Conditional Tests. But you noticed that we cannot send separate parameters per each iteration in repeated tests. But in parameterized tests you can run the test several times by giving different set of inputs 🤩
There are several annotations that we can use with parameterized tests.
@ValueSource
@MethodSource
@CsvSource
@CsvFileSource
@ValueSource
This annotation allows us to provide inputs directly as a parameter value through the annotation. It supports different types of literals like String, Int, Long, Short, Float, Double, Byte, Char, and Class. Let's go through a coding example.
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class TestManageEmployees {
@DisplayName("Add Employee for different parameters")
@ParameterizedTest
@ValueSource(strings = {"0123456789", "0987654321"})
public void TestParameterizedTestValueSource(String contact_number) {
ManageEmployees employees = new ManageEmployees();
employees.addEmployee("Bella", "Swan", contact_number);
Assertions.assertFalse(employees.getEmployees().isEmpty());
Assertions.assertEquals(1, employees.getEmployees().size());
System.out.println("Line with the contact number: " + contact_number);
}
}
As you can see we have used two test annotations to write the above test; @ParameterizedTest
and @ValueSource
. What this test does is creating two employees with same first and last name, but with different contact numbers. We have passed a string array of phone numbers to @ValueSource
. Inside the test I added a print statement for you to understand easily about the test execution. Hence you can see the below output once you run the test.
@MethodSource
In @ValueSource
we have a small restriction as we can only pass simple input values. But in real world you may have to pass complex objects or lists as parameters. In such cases you should use @MethodSource
.
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.Arrays;
import java.util.List;
public class TestManageEmployees {
private static List<String> contactNumbersList() {
return Arrays.asList("0123456789", "0987654321");
}
@DisplayName("Add Employee using MethodSource")
@ParameterizedTest
@MethodSource("contactNumbersList")
public void TestParameterizedTestMethodSource(String contact_number) {
ManageEmployees employees = new ManageEmployees();
employees.addEmployee("Bella", "Swan", contact_number);
Assertions.assertFalse(employees.getEmployees().isEmpty());
Assertions.assertEquals(1, employees.getEmployees().size());
System.out.println("Line with the contact number: " + contact_number);
}
}
As you can see in the above example I have declared a new method named contactNumbersList()
which creates a list of contact numbers. Then we pass this list into our test method using the annotation @MethodSource
. The test method TestParameterizedTestMethodSource()
takes elements one by one from the list that we have passed to @MethodSource
. Hence, the execution of this test gives the below output.
@CsvSource
Incase you are wondering what CSV is, it stands for Comma Separated Values. Yes, your guess is correct. This annotation allows us to pass a parameter list with elements which are separated by commas, in other words Csv literals.
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
public class TestManageEmployees {
@DisplayName("Add Employee using CsvSource")
@ParameterizedTest
@CsvSource({"0123456789", "0987654321"})
public void TestParameterizedTestCsvSource(String contact_number) {
ManageEmployees employees = new ManageEmployees();
employees.addEmployee("Jacob", "Black", contact_number);
Assertions.assertFalse(employees.getEmployees().isEmpty());
Assertions.assertEquals(1, employees.getEmployees().size());
System.out.println("Line with the contact number: " + contact_number);
}
}
In the above code you can see a list of contact numbers separated by commas is included within curly brasses - {} and has given to the annotation @CsvSource
. When the test runs,
@CsvFileSource
This annotation is a bit similar to CsvSource annotation. The difference in here is, instead of referencing the list of comma separated strings directly, here we provide the reference to a Csv file. Inside the test directory let's create a new directory named resources. In that directory let's create a new file as data.csv.
Directory structure: test -> resources -> data.csv
In data.csv I saved three contact numbers;
0123456789
0987654321
0192837465
Now let's look at the test method code and see how we can pass the reference of this file.
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
public class TestManageEmployees {
@DisplayName("Add Employee using CsvFileSource")
@ParameterizedTest
@CsvFileSource(resources = "/data.csv")
public void TestParameterizedTestCsvFileSource(String contact_number) {
ManageEmployees employees = new ManageEmployees();
employees.addEmployee("Alice", "Cullen", contact_number);
Assertions.assertFalse(employees.getEmployees().isEmpty());
Assertions.assertEquals(1, employees.getEmployees().size());
System.out.println("Line with the contact number: " + contact_number);
}
}
We give the reference to the file through the annotation @CsvFileSource
. Then the values in that csv file are read by the test method. After executing test gives the below output.
Phew, that's a quite a long tutorial I must say 🥵 Ah ha no, not finished yet 😏 We have another tutorial on Nested Tests 🤪
Top comments (0)