Testing the unique method

The Apache Commons Lang offers the unique method. Following is its adapted Javadoc:

Returns an array consisting of the unique values in data. The return array is sorted in descending order. Empty arrays are allowed, but null arrays result in a NullPointerException. Infinities are allowed.

Parameters:

  • data: Array to scan

The method returns a descending list of values included in the input array. It throws a NullPointerException if data is null.

You can see its implementation next.

Listing 5.6 Implementation of the unique method

public static int[] unique(int[] data) {
  TreeSet<Integer> values = new TreeSet<Integer>();   ❶
  for (int i = 0; i < data.length; i++) {
     values.add(data[i]);
  }
 
  final int count = values.size();
  final int[] out = new int[count];                   ❷
 
  Iterator<Integer> iterator = values.iterator();
  int i = 0;
  while (iterator.hasNext()) {                        ❸
     out[count - ++i] = iterator.next();
  }
  return out;
}

❶ Uses a treeset to filter out repeated elements

❷ Creates the new array using the size of the tree

❸ Visits the treeset and adds the elements to the new array

Let’s go straight to property-based testing. Here, we focus on the main property of the method: given an array of integers, the method returns a new array containing only the unique values of the original array, sorted in descending order. This is the property we will embed in a jqwik test.

Our test works as follows. First we create a random list of integers. To ensure that the list has repeated numbers, we create a list of size 100 and limit the range of integers to [0,20]. We then call the unique method and assert that the array contains all the elements of the original array, does not have duplicates, and is sorted in descending order. Let’s write that down in jqwik.

Listing 5.7 Property-based test for the unique method

public class MathArraysPBTest {
 
  @Property
  void unique(
   @ForAll
   @Size(value = 100)                                          ❶
   List<@IntRange(min = 1, max = 20) Integer>                  ❷
   numbers) {
 
    int[] doubles = convertListToArray(numbers);
    int[] result = MathArrays.unique(doubles);
 
    assertThat(result)
        .contains(doubles)                                     ❸
        .doesNotHaveDuplicates()                               ❹
        .isSortedAccordingTo(reverseOrder());                  ❺
  }
 
  private int[] convertListToArray(List<Integer> numbers) {    ❻
    int[] array = numbers
      .stream()
      .mapToInt(x -> x)
      .toArray();
 
    return array;
  }
}

❶ An array of size 100

❷ With values in [0, 20]. Given the size of the array (100), we know it will contain repeated elements.

❸ Contains all the elements

❹ No duplicates

❺ In descending order

❻ Utility method that converts a list of integers to an array

TIP Note how AssertJ simplifies our lives with its many ready-to-use assertions. Without it, the developer would have to write lots of extra code. When writing complex assertions, check the documentation to see whether something is available out of the box!

NOTE One of my students noticed that even if we do not restrict the integer list to numbers in [0, 20], jqwik will produce lists with duplicated elements. In his exploration, he noticed that 11% of the produced arrays had a duplicated element. As a tester, you may want to consider whether 11% is a good rate. To measure this, my student used jqwik’s statistics feature which enables you to measure the distribution of the input values.

Jqwik did not find any inputs that would break the program. So, our implementation seems to work. Let’s move to the next example.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *