Writing Parameterized Test Cases in Junit

20:42

Many times we want to execute the same test case with different input and expectations. Instead of writing each test separately, it is much better to abstract the actual test into a class and inject input values and expected results into the test class. Junit4 provides Parametrized test, which is a standard solution to achieve this.

Let’s write a simple square() method to return square of a number. We’ll consider this square() method for writing our Parametrized test case:
package blog.techypages.junit.test;

/**
 * Utility class to support various mathematical functions.
 * 
 * @author abhishek
 *
 */
public class MathUtils {
    
    /**
     * Returns square of a number
     * @param number
     * @return
     */
    public static int square(int number){
        return number*number;
    }

}


To write Parametrized test cases a test class should satisfy following conditions:
       1. Test class should be annotated with @RunWith(Parameterized.class) annotation.
       2. Test class should have a static public method annotated with @Parameters annotation and returning                   a collection of test data elements (which in turn are stored in an array).
       3. Test class should have a single constructor which accepts test data elements from the previously                           mentioned array and inject into object appropriate states.

When running a parametrized test class, a new test class is created for the cross-product of the test methods and the test data elements. It means for a test class if there is 1 test case and 5 input data then there will be total 5(1*5) instances of parameterized test class with their own set of input data.

Let’s write Parameterized test to test square() method for inputs [0,5] and their corresponding expectations.
package blog.techypages.junit.test;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/**
 * Parameterized test case.
 * 
 * @author abhishek
 *
 */
@RunWith(Parameterized.class)
public class SquareTest {

    @Parameters(name = "Test#{index}: square[{0}]={1}")
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[][] { 
                 {0, 0}, {1, 1}, {2, 4}, {3, 9}, {4, 16}, {5, 25}
           });
    }
    
    private int input;
    private int expected;
    
    public SquareTest(int input, int expected) {
        this.input = input;
        this.expected = expected;
    }

    @Test
    public void testSquare() {
        System.out.println("Test Case Instance: " + this);
        assertEquals(expected, MathUtils.square(input));
    }

}


Result:
Console Prints:
Test Case Instance: blog.techypages.junit.test.SquareTest@2ca6d51e
Test Case Instance: blog.techypages.junit.test.SquareTest@2aca0115
Test Case Instance: blog.techypages.junit.test.SquareTest@340d1fa5
Test Case Instance: blog.techypages.junit.test.SquareTest@4998a455
Test Case Instance: blog.techypages.junit.test.SquareTest@444cee32
Test Case Instance: blog.techypages.junit.test.SquareTest@16aa37a6


It is clearly evident from the console prints that there are total 6(1 test-case*6 input) instances of SqaureTest class.

Identify Individual Test Case
In order to easily identify the individual test cases in a Parameterized test, you may provide a name using the @Parameters annotation. This name is allowed to contain placeholders that are replaced at runtime:

      1. {index}      : the current parameter index
      2. {0}, {1}, … : the first, second, and so on, parameter value

In our example we named the test case as "
Test#{index}: square[{0}]={1}". Actual test names can be easily viewed in the Result snap.

Writing Parameterized test is pretty simple and useful to run the same test for various inputs.

Hope this article helped. Happy learning... :)

You Might Also Like

0 comments