JUnitParams – parameterized unit tests
Less unit test code doesn’t necessarily result into poor coverage. I’ve recently entered the paradigm of parameterized tests when refactoring a larger test suite. I ended up writing significantly less code without compromising on the extent. In fact, adding a few corner cases was almost a no-brainer. In this post I’d like to share my experience with JUnitParams and discuss advantages of parameterized unit tests.
public interface ISort { // Identifies the algorithm String getName(); // Sorts the given numeric sequence Result sort(int... x); } // Implementation - details are not important just now public class InsertSort implements ISort {..} public class QuickSort implements ISort {..} public class SelectSort implements ISort {..}
public class Result { private String algorithm; private List<int[]> steps = new ArrayList<int[]>(); .. @Override public String toString() { // pretty-prints the sorting result, includes individual steps } }
public class StandardSortTest { private InsertSort insertSort = new InsertSort(); .. @Test public void insertSortNull() { assertResult(insertSort.sort(null), new ResultBuilder(insertSort.getName()).build()); } @Test public void insertSortEmpty() { assertResult(insertSort.sort(new int[] {}), new ResultBuilder(insertSort.getName()).build()); } @Test public void insertSort() { assertResult(insertSort.sort(input), new ResultBuilder(insertSort.getName()) .addStep(3, 7, 4, 9, 5, 2, 6, 1) .addStep(3, 7, 4, 9, 5, 2, 6, 1) .addStep(3, 4, 7, 9, 5, 2, 6, 1) .addStep(3, 4, 7, 9, 5, 2, 6, 1) .addStep(3, 4, 5, 7, 9, 2, 6, 1) .addStep(2, 3, 4, 5, 7, 9, 6, 1) .addStep(2, 3, 4, 5, 6, 7, 9, 1) .addStep(1, 2, 3, 4, 5, 6, 7, 9) .build() ); } // etc, similar for the other 2 sorting algorithms }
import junitparams.JUnitParamsRunner; import junitparams.Parameters; import org.junit.runner.RunWith; .. @RunWith(JUnitParamsRunner.class) public class ParameterizedSortTest { @Test @Parameters public void sort(ISort sortAlg, int[] toSort, Result expectedResult) { Result result = sortAlg.sort(toSort); Assert.assertEquals(result.toString(), expectedResult.toString()); } // Provides parameters // see: https://code.google.com/p/junitparams private Object[] parametersForSort() {..} }
Someone forgot to check those unwieldy null values |
Well, let’s see what the report would look like in case of the parameterized tests comprising a single test method:
Hover over effect reveals parameter values (captured in IntelliJ IDEA 12) |
As you can see, the results are determined by the sets of passed parameters and not by the number of written test methods. I find it highly useful as it allows for data-driven tests with a minimal functional overhead.
Thanks for reading up to this point and I hope you feel inspired. Please find a complete example under the link below. The example demoes an additional feature – test data providers – which allows to keep data sets separate from the actual test code.
Source Code