Monday 2 July 2018

Junit: parameterized tests

Parameterized tests are used to repeat the same test against different input values.

For example, I written an application that compute the factorial of a number.
package com.sample.arithmetic;

public class Factorial {

 public int factorial(int num) throws Exception {
  if (num < 0) {
   throw new IllegalArgumentException("Factorial is not computed for negative numbers");
  }

  int result = 1;

  for (int i = 2; i <= num; i++) {
   result *= i;
  }

  return result;
 }
}

I would like to test the above application with below input-output combinations.

Input
Expected Output
0
1
1
1
5
120
10
3628800

I written the test application like below.


FactorialTest.java
package com.sample.arithmetic;

import static org.junit.Assert.assertEquals;

import org.junit.Test;

/**
 * Test cases follow below naming convention. methodName_input_output format.
 * 
 * @author krishna
 *
 */
public class FactorialTest {
 @Test
 public void factorial_0_1() throws Exception {
  Factorial factorial = new Factorial();

  long actual = factorial.factorial(0);
  long expected = 1;

  assertEquals(expected, actual);
 }

 @Test
 public void factorial_1_1() throws Exception {
  Factorial factorial = new Factorial();

  long actual = factorial.factorial(1);
  long expected = 1;

  assertEquals(expected, actual);
 }

 @Test
 public void factorial_5_120() throws Exception {
  Factorial factorial = new Factorial();

  int actual = factorial.factorial(5);
  int expected = 120;

  assertEquals(expected, actual);
 }

 @Test
 public void factorial_10_3628800() throws Exception {
  Factorial factorial = new Factorial();

  int actual = factorial.factorial(10);
  int expected = 3628800;

  assertEquals(expected, actual);
 }

}

As you observe above test class, all the test cases following the same pattern and leads to lot of redundant code.
a.   Calling the factorial function with some input
b.   Verifying the output with expected value.

By using parameterized test, you can remove this redundant code.

Step 1:  Create a parameterized test class.
@RunWith(Parameterized.class)
public class FactorialTest {


}


Step 2: Define input and expectedResult fields.

Step 3: Define a constructor that initializes input and expectedResult fields.

Step 4: Create a static method that generates and returns test data. Annotate the static method with ‘@parameterized.Parameters’ annotation.

Step 5: Now write the test case.
         @Test
         public void testFactorial() throws Exception {
                  int output = fact.factorial(input);
                  assertEquals(expectedResult, output);
         }

Find the below working example.

FactorialTest.java
package com.sample.arithmetic;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;

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

/**
 * Test cases follow below naming convention. methodName_input_output format.
 * 
 * @author krishna
 *
 */
@RunWith(Parameterized.class)
public class FactorialTest {
 private int input;
 private int expectedResult;

 private Factorial fact;

 @Before
 public void init() {
  fact = new Factorial();
 }

 @Parameterized.Parameters
 public static Iterable<Object[]> data() {
  return Arrays.asList(new Object[][] { { 0, 1 }, { 1, 1 }, { 5, 120 }, { 10, 3628800 } });
 }

 public FactorialTest(int input, int expectedResult) {
  this.input = input;
  this.expectedResult = expectedResult;
 }

 @Test
 public void testFactorial() throws Exception {
  int output = fact.factorial(input);
  assertEquals(expectedResult, output);
 }

}


When I ran the above application, it executes 4 test cases. I can able to see below kind of report.




Previous                                                 Next                                                 Home

No comments:

Post a Comment