DEV Community

Cover image for Property-Based Matrix Testing in Java
Tomer Figenblat
Tomer Figenblat

Posted on • Edited on

Property-Based Matrix Testing in Java

I've used a common approach for property-based matrix testing in Java. Using JUnit's ParameterizedTest and a MethodSource annotations to point to a method as an argument supplier that spits out a stream representing a matrix.

It's pretty straightforward, but the more parameter types we have in our matrix, the harder it is to read or write the method supplying them. 😵

Let's take a look.
First, these are the two types for our matrix, these should spit out 6 test cases:

  enum Direction {
    INCOMING,
    OUTGOING
  }

  enum Status {
    SUCCESS,
    FAILURE,
    WAITING
  }
Enter fullscreen mode Exit fullscreen mode

Implementing a matrix from these Enums with JUnit's ParameterizedTest and a MethodSource:

  @ParameterizedTest
  @MethodSource("getArguments")
  void using_junit_parameterized_test_with_method_source(
      final Direction direction, final Status status) {
    assertTrue(true);
  }

  static Stream<Arguments> getArguments() {
    return Stream.of(Direction.values())
        .flatMap(d -> Stream.of(Status.values()).map(s -> arguments(d, s)));
  }
Enter fullscreen mode Exit fullscreen mode

Adding members to the existing Enums will dynamically increase the matrix and, therefore, the number of tests performed; there's no need to modify the test code.

But, adding a third type to the matrix and the getArguments method will start losing its readability.

Lately, I discovered JUnit Pioneer, which is a JUnit 5 Extension Pack. Using its CartesianProductTest and CartesianEnumSource annotations, we can implement the same matrix simply and elegantly: 😃

  @CartesianProductTest
  @CartesianEnumSource(Direction.class)
  @CartesianEnumSource(Status.class)
  void using_junit_pioneer_cartesian_product_test_with_enum_source(
      final Direction direction, final Status status) {
    assertTrue(true);
  }
Enter fullscreen mode Exit fullscreen mode

This will spit out the same matrix, only now, adding a third element is quite simple: add another CartesianEnumSource annotation.

You can find other types of sources beside Enums, in JUnit Pioneer's Documentation.

As demonstrated in this repository, executing both matrix tests will print out:

[INFO] '-- JUnit Jupiter [OK]
[INFO]   '-- Property Based Matrix Test [OK]
[INFO]     +-- using junit pioneer cartesian product test with enum source (Direction, Status) [OK]
[INFO]     | +-- [1] INCOMING, SUCCESS [OK]
[INFO]     | +-- [2] INCOMING, FAILURE [OK]
[INFO]     | +-- [3] INCOMING, WAITING [OK]
[INFO]     | +-- [4] OUTGOING, SUCCESS [OK]
[INFO]     | +-- [5] OUTGOING, FAILURE [OK]
[INFO]     | '-- [6] OUTGOING, WAITING [OK]
[INFO]     '-- using junit parameterized test with method source (Direction, Status) [OK]
[INFO]       +-- [1] INCOMING, SUCCESS [OK]
[INFO]       +-- [2] INCOMING, FAILURE [OK]
[INFO]       +-- [3] INCOMING, WAITING [OK]
[INFO]       +-- [4] OUTGOING, SUCCESS [OK]
[INFO]       +-- [5] OUTGOING, FAILURE [OK]
[INFO]       '-- [6] OUTGOING, WAITING [OK]
Enter fullscreen mode Exit fullscreen mode

Check out the code for this tutorial in Github.

Top comments (0)