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.
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;
}
}
❷ With values in [0, 20]. Given the size of the array (100), we know it will contain repeated elements.
❻ 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.
Leave a Reply