Core Java

Parameterized Test Runner in JUnit

We all have written unit tests where in a single test tests for different possible input-output combinations. Lets look how its done by taking a simple fibonacci series example.

The below code computes the fibonacci series for number of elements mentioned:
 
 
 
 
 
 

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

public class Fibonacci{

  public List<Integer> getFiboSeries(int numberOfElements) {
    List<Integer> fiboSeries = new ArrayList<>(numberOfElements);
    for (int i = 0; i < numberOfElements; i++) {
      //First 2 elements are 1,1
      if (i == 0 || i == 1) {
        fiboSeries.add(i, 1);
      } else {
        int firstPrev = fiboSeries.get(i - 2);
        int secondPrev = fiboSeries.get(i - 1);
        int fiboElement = firstPrev + secondPrev;
        fiboSeries.add(i, fiboElement);
      }
    }
    return fiboSeries;
  }

}

Lets see the conventional way of testing the above code with multiple input values

import java.util.List;
import org.junit.Test;
import java.util.Arrays;
import static org.junit.Assert.*;

public class FibonacciCachedTest {

  /**
   * Test of getFiboSeries method, of class Fibonacci.
   */
  @Test
  public void testGetFiboSeries() {
    System.out.println("getFiboSeries");
    int numberOfElements = 5;
    Fibonacci instance = new Fibonacci();
    List<Integer> expResult = Arrays.asList(1, 1, 2, 3, 5);
    List<Integer> result = instance.getFiboSeries(numberOfElements);
    assertEquals(expResult, result);

    numberOfElements = 10;
    expResult = Arrays.asList(1, 1, 2, 3, 5, 8, 13, 21, 34, 55);
    result = instance.getFiboSeries(numberOfElements);
    assertEquals(expResult, result);

  }
}

So we have been able to test for 2 inputs, imagine extending the above for more number of inputs? Unnecessary bloat up in the test code.

JUnit provides a different Runner called Parameterized runner which exposes a static method annotated with @Parameters. This method has to be implemented to return the inputs and expected output collection which will be used to run the test defined in the class. Lets look at the code which does this:

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
public class ParametrizedFiboTest {

  private final int number;
  private final List<Integer> values;

  public ParametrizedFiboTest(FiboInput input) {
    this.number = input.number;
    this.values = input.values;
  }

  @Parameterized.Parameters
  public static Collection<Object[]> fiboData() {
    return Arrays.asList(new Object[][]{
      {new FiboInput(1, Arrays.asList(1))},
      {new FiboInput(2, Arrays.asList(1, 1))},
      {new FiboInput(3, Arrays.asList(1, 1, 2))},
      {new FiboInput(4, Arrays.asList(1, 1, 2, 3))},
      {new FiboInput(5, Arrays.asList(1, 1, 2, 3, 5))},
      {new FiboInput(6, Arrays.asList(1, 1, 2, 3, 5, 8))}
    });
  }

  @Test
  public void testGetFiboSeries() {
    FibonacciUncached instance = new FibonacciUncached();
    List<Integer> result = instance.getFiboSeries(this.number);
    assertEquals(this.values, result);
  }

}

class FiboInput {

  public int number;
  public List<Integer> values;

  public FiboInput(int number, List<Integer> values) {
    this.number = number;
    this.values = values;
  }
}

This way we would just need to add a new input and expected output in the fiboData() method to get this working!

Reference: Parameterized Test Runner in JUnit from our JCG partner Mohamed Sanaulla at the Experiences Unlimited blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Sankalp suryawanshi
Sankalp suryawanshi
9 years ago

Hi Sanaulla

Thanks for post showing use of parameterized junit. However it would be great if you can also mention at what point actually method annotated with @Parameterized.Parameters gets called. Probably I am missing some thing, it doesn’t look like it actually calls the annotated method?
I appreciate your efforts.

Thanks
Sankalp

Back to top button