This library provides support classes for writing JUnit tests. It supports both Junit4 and JUnit5.
Permutaions work like this:
@Test
void print() {
Permutation.of("A", "B", "C")
.forEach(System.out::println);
}
This will produce the following output:
[A, B, C]
[A, C, B]
[B, A, C]
[B, C, A]
[C, A, B]
[C, B, A]
Testing using permutations:
@TestFactory
// Exhaustively tests that the order of setter invocation does not matter
Stream<DynamicTest> demo() {
// Operations
final Consumer<MyBean> setA = myBean -> myBean.setA(1);
final Consumer<MyBean> setB = myBean -> myBean.setB(2);
final Consumer<MyBean> setC = myBean -> myBean.setC(3);
final MyBean expected = new MyBean(1, 2, 3);
// DynamicTests
return DynamicTest.stream(Permutation.of(setA, setB, setC),
Objects::toString,
operations -> {
final MyBean actual = new MyBean();
operations.forEach(oper -> oper.accept(actual));
assertEquals(expected, actual);
});
}
Combinations work like this:
@Test
void print() {
Combination.of("A", "B", "C")
.forEach(System.out::println);
}
This will produce the following output:
[]
[A]
[B]
[C]
[A, B]
[A, C]
[B, C]
[A, B, C]
Testing using combinations:
@TestFactory
// Try all combinations of cosmic ray interference
@TestFactory
// Try all combinations of the Robot state machine
Stream<DynamicTest> demo() {
return DynamicTest.stream(Combination.<Consumer<FaultTolerantBitSet>>of(
FaultTolerantBitSet::cosmicRayBit3,
FaultTolerantBitSet::cosmicRayBit23,
FaultTolerantBitSet::cosmicRayBit13),
Objects::toString,
operations -> {
final FaultTolerantBitSet bitSet = new FaultTolerantBitSet();
operations.forEach(oper -> oper.accept(bitSet));
assertTrue(bitSet.isValid());
});
}
Combinations and Permutaions can be combined to create powerful exhaustive test vectors:
@Test
void demo() {
Combination.of("A", "B", "C")
.flatMap(Permutation::of)
.forEach(System.out::println);
}
This will produce the following output:
[A]
[B]
[C]
[A, B]
[B, A]
[A, C]
[C, A]
[B, C]
[C, B]
[A, B, C]
[A, C, B]
[B, A, C]
[B, C, A]
[C, A, B]
[C, B, A]
Products are equivalent to nested loops but are easier to convert to a Stream
of DynamicTest
objects:
@Test
void print() {
Product.of(Arrays.asList("A", "B", "C"), Arrays.asList(1, 2, 3))
.forEach(System.out::println);
}
This will produce the following output:
Product2Impl{first=A, second=1}
Product2Impl{first=A, second=2}
Product2Impl{first=A, second=3}
Product2Impl{first=B, second=1}
Product2Impl{first=B, second=2}
Product2Impl{first=B, second=3}
Product2Impl{first=C, second=1}
Product2Impl{first=C, second=2}
Product2Impl{first=C, second=3}
Products can use built-in tuples like Product2Impl
or we can provide custom constructors to use our own.
Testing using combinations:
@TestFactory
// Exhaustively tests if various empty collections invariants holds
Stream<DynamicTest> demo() {
// Operations
final List<Collection<Integer>> collections = Arrays.asList(new LinkedList<>(), new ArrayList<>(), new HashSet<>());
// Operations
final Consumer<Collection<Integer>> empty =
c -> assertTrue(c.isEmpty(), c.getClass() + ".empty() was false");
final Consumer<Collection<Integer>> size =
c -> assertEquals(0, c.size(), c.getClass() + ".size() != 0");
final Consumer<Collection<Integer>> streamCount =
c -> assertEquals(0, c.stream().count(), c.getClass() + ".stream().count() != 0");
final List<Consumer<Collection<Integer>>> operations = Arrays.asList(empty, size, streamCount);
// DynamicTests
return DynamicTest.stream(Product.of(collections, operations),
Objects::toString,
tuple -> {
tuple.second().accept(tuple.first());
});
}