JUnit Parameterized Tests

Filed Under: JUnit

JUnit Parameterized Tests allow us to run a test method multiple times with different arguments. JUnit 5 provides a lot of ways to pass parameters to a test method.

JUnit Parameterized Tests

We need following additional dependency to use parameterized tests in our test cases.


<dependency>
	<groupId>org.junit.jupiter</groupId>
	<artifactId>junit-jupiter-params</artifactId>
	<version>5.2.0</version>
	<scope>test</scope>
</dependency>

We have to use @ParameterizedTest with the test method instead of generic @Test annotation.

We also have to provide a source that will generate the arguments for the method. There are many types of sources we can define and use in our parameterized test methods.

JUnit Parameterized Test with @ValueSource

This is the simplest form of parameterized test, we can use @ValueSource to pass the arguments array. We can pass primitive data types array, string array or class array using ValueSource annotation.


@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void test_ValueSource(int i) {
	System.out.println(i);
}

@ParameterizedTest
@ValueSource(strings = { "1", "2", "3" })
void test_ValueSource_String(String s) {
	assertTrue(Integer.parseInt(s) < 5);
}

JUnit @ParameterizedTest with @EnumSource

@EnumSource allows us to pass Enums to our test methods.


@ParameterizedTest
@EnumSource(ElementType.class)
void test_EnumSource(ElementType et) {
	System.out.println(et);
}

If we want only specific values from the Enum, we can do that using EnumSource name parameter.


@ParameterizedTest
@EnumSource(value = ElementType.class, names = { "TYPE", "METHOD", "FIELD" })
void test_EnumSource_Extended(ElementType et) {
	assertTrue(EnumSet.of(ElementType.FIELD, ElementType.TYPE, ElementType.METHOD).contains(et));
}

JUnit @ParameterizedTest with @MethodSource

We can use @MethodSource to specify a factory method for test arguments. This method can be present in the same class or any other class too. The factory method should be static and return Strem, Iterator, Iterable or array of elements.


@ParameterizedTest
@MethodSource("ms")
void test_MethodSource(String s) {
	assertNotNull(s);
}

static Stream<String> ms() {
	return Stream.of("A", "B");
}

We can also use MethodSource to pass multiple parameters to the test method. In this case, we will have to use Arguments API. Let’s define a separate class with factory method source.


package com.journaldev.parameterizedtests;

import java.util.stream.Stream;

import org.junit.jupiter.params.provider.Arguments;

public class MethodSources {

	public static Stream<Arguments> msMP() {
		return Stream.of(Arguments.of(1, "A"), Arguments.of(2, "B"), Arguments.of(3, "C"));
	}
}

Corresponding JUnit parameterized test method would be defined as:


@ParameterizedTest
@MethodSource("com.journaldev.parameterizedtests.MethodSources#msMP")
void test_MethodSource_MultipleParams(int i, String s) {
	assertTrue(4 > i);
	assertTrue(Arrays.asList("A", "B", "C").contains(s));
}

JUnit MethodSource is very similar to TestNG DataProvider annotation.

JUnit @ParameterizedTest with @CsvSource

We can also pass CSV values to the test method. We can specify the delimiter for multiple arguments in the test method.


@ParameterizedTest
@CsvSource(delimiter='|', value= {"1|'A'","2|B"})
void test_CsvSource(int i, String s) {
	assertTrue(3 > i);
	assertTrue(Arrays.asList("A", "B", "C").contains(s));
}

JUnit Parameterized Test with CSV File

We can use @CsvFileSource annotation to pass CSV data from a file to the parameterized test method. We can skip the header rows and define our custom delimiter too.

Let’s say we have country_code.csv file defined as:


Country,TelephoneCode
USA,1
India,91

Here is the test method where CSV file data will be used for arguments mapping.


@ParameterizedTest
@CsvFileSource(resources = "/country_code.csv", numLinesToSkip = 1)
void test_CsvFileSource(String country, int code) {
    assertNotNull(country);
    assertTrue(0 < code);
}

JUnit Parameterized Tests with Objects

So far we have used primitives and strings in our examples, but in real life, we have to pass objects most of the times. We can use @MethodSource to achieve this functionality.

Let’s say we have a Book class defined as:


class Book {
	private String title;
	// standard getter setters

	public Book(String t) {
		this.title = t;
	}
	
	@Override
	public String toString() {
		return title;
	}
}

Now we can pass Book object to our test methods using below factory method.


static Book[] mpBooks() {
	return new Book[] {new Book("Harry Potter"), new Book("Five Point Someone")};
}

@ParameterizedTest
@MethodSource("mpBooks")
void test_MethodSource_Objects(Book b) {
	assertNotNull(b.getTitle());
}

Notice that this time I am returning an array of Books, earlier I was returning Stream of elements.

JUnit Parameterized Tests Arguments Verification

If you are running test cases through Eclipse, you can check method arguments to make sure correct values are being passed to the parameterized tests.

JUnit Parameterized Tests

JUnit Test Methods Argument Conversion

JUnit provides built-in support for many type converters. Some of them are int to long, string to boolean and vice versa, string to enum, date time objects. Below code will also work and JUnit will automatically call our Book class constructor to convert String values to Book object.


@ParameterizedTest
@ValueSource(strings = {"Harry Potter", "Hamlet"})
void test_ValueSource_Objects(Book b) {
	assertNotNull(b.getTitle());
}

However, this could lead to errors when test cases are executed if our Book class constructor changes. It’s better to use MethodSource and provide our own mechanism for object creation.

Summary

JUnit Parameterized Tests were a much-needed feature and it’s good to see so many options to provide arguments to our test methods.

You can check out JUnit example project with complete examples at our GitHub Repository.

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages