[Java] How to write Parameterized Unit Tests
by Riley MacDonald, November 29, 2017

Parameterized tests can be very helpful when testing expected results against various input data. Instead of writing several tests you can parameterize your test values are write a single method to verify the results.

Sample Problem
Here’s how a test for the following StringMutator class might look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Example class to test
public class StringMutator {
    public static String captilizeString(String input) {
        return input.toUpperCase();
    }
}
 
// Example test (simplified for clarity)
public class ExampleUnitTest {
    @Test
    public void testCapitalizeString() {
        assertEquals(StringMutator.captilizeString("something"), "SOMETHING");
        assertEquals(StringMutator.captilizeString("Something"), "SOMETHING");
        assertEquals(StringMutator.captilizeString("W3irdData"), "W3IRDDATA");
        assertEquals(StringMutator.captilizeString(""), "");
        assertEquals(StringMutator.captilizeString("SS"), "SS");
    }
}

Parameterized Testing
While this test (while virtually pointless) is a potential candidate for parameterized testing. The test data can be “parameterized” the above test can be reduced to a single line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.example.rileymacdonald.parameterizedtest;
 
import org.junit.Test;
 
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
 
 
import java.lang.Iterable;
import java.util.Arrays;
 
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.runners.Parameterized.Parameters;
 
@RunWith(Parameterized.class)
public class ExampleUnitTest {
    @Parameters
    public static Iterable<Object[][]> data() {
        return Arrays.asList(new Object[][]{
                {"something", "SOMETHING"},
                {"Something", "SOMETHING"},
                {"W3irdData", "W3IRDDATA"},
                {"", ""},
                {"SS", "SS"}
        });
    }
 
    private final String input;
    private final String expectedResult;
 
    public ExampleUnitTest(String input, String expectedResult) {
        this.input = input;
        this.expectedResult = expectedResult;
    }
 
    @Test
    public void testCapitalizeString() {
        assertThat(StringMutator.captilizeString(input), is(equalTo(expectedResult)));
    }
 
}

More data can be added to the @Parameters object. For example your test method might take more than one argument. There’s a bit of setup involved but the tests become more readable / maintainable when the datasets grow.

TNG – JUnit Data Provider Library
I recently wrote some tests using the TNG/junit-dataprovider library. While it adds a test dependency to your module it cuts down the boilerplate involved. Here’s an example of how this same test would look using @DataProvider:

Add the test dependency to your build.gradle

1
2
testImplementation 'junit:junit:4.12'
testImplementation 'com.tngtech.java:junit-dataprovider:1.11.0'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
 
import org.junit.Test;
import org.junit.runner.RunWith;
 
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertThat;
 
@RunWith(DataProviderRunner.class)
public class ExampleUnitTest {
 
    // Declare a data provider
    @DataProvider
    public static Object[][] provideTestStrings() {
        return new Object[][]{
                {"something", "SOMETHING"},
                {"Something", "SOMETHING"},
                {"W3irdData", "W3IRDDATA"},
                {"", ""},
                {"SS", "SS"}
        };
    }
 
    // Reference the declared data provider
    @UseDataProvider("provideTestStrings")
    @Test
    public void testCapitalizeString(String input, String expected) {
        // The method arguments represent the data coming from the above data provider
        assertThat(StringMutator.captilizeString(input), is(equalTo(expected)));
    }
}
Open the comment form

Leave a comment:

Comments will be reviewed before they are posted.

User Comments:

Be the first to leave a comment on this post!