1

I'm working with OptionalAssert class of AssertJ and I need to implement a JUnit ParameterizedTest that will check for presence or emptiness of an Optional instance in a dynamic way:

@ParameterizedTest
@MethodSource(/* values */)
void test_presence(Optional<String> opt, boolean empty) {
    assertThat(opt) // -> .isPresent() / .isEmpty();
}

In a non-parametrised test I would use .isPresent() or .isEmpty() methods to execute the check, but in this case I'd like to apply something like .isPresent(true/false).

I can't find a method like this in the JavaDoc so I'm wondering if there is an alternative approach to this (or should I just deal with an if/else?)

UPDATE I know that I could implement something like so (as suggested in an answer):

assertThat(opt.isPresent()).isEqualTo(present);

but I'd like to maintain a fluent approach, and code similar to this:

assertThat(opt)
    .isPresent(present) // true/false
    .hasValueSatisfying(...)
    .hasValueSatisfying(...)
    // etc.
davioooh
  • 23,742
  • 39
  • 159
  • 250
  • I imagine that `@ValueSource` is not what you actually would use as it does not support two method parameters, right? – Stefano Cordio Nov 24 '21 at 11:08
  • @StefanoCordio yes, I actually have a MethodSource – davioooh Nov 24 '21 at 13:57
  • not sure if it's possible in your case but can you split the parameterized tests in two parameterized tests: one for the empty case and one for the present case? Otherwise I think a `if/else` is a pragmatic solution – Joel Costigliola Nov 24 '21 at 22:36
  • @JoelCostigliola create 2 parametrized test cases (one for present, one for empty), could be a nice approach. Thanks. Anyway I'd like to know if ther's a more "compact" way to achieve this. – davioooh Nov 25 '21 at 14:35
  • It's not the solution but another technique is to use `opt.ifPresent(value -> assertThat(value).isEqualTo("foo"))` which would execute the given assertions (I put only one in my example but you can add more). – Joel Costigliola Nov 25 '21 at 20:45

2 Answers2

1

You can use boolean assert instead

assertThat(opt.isEmpty()).isEqualTo(empty)

You can use two asserts instead of one, but for fluent assert you can use org.assertj.core.api.Condition.

  @ParameterizedTest
  @MethodSource("t")
  public void test(boolean empty, Object obj) {
    Condition<Optional<Object>> condition = new Condition<>(empty ? Optional::isEmpty : Optional::isPresent,
        "empty=%s", empty);
    assertThat(Optional.ofNullable(obj)).is(condition);
  }

  public static Stream<Arguments> t() {
    return Stream.of(Arguments.of(false, new Object()), Arguments.of(true, null), Arguments.of(true, new Object()));
  }

On assertion error following message is shown

java.lang.AssertionError: 
Expecting:
  Optional[java.lang.Object@28bdbe88]
to be empty=true
geobreze
  • 2,274
  • 1
  • 10
  • 15
1

You can simply test like this:

@ParameterizedTest
@ValueSource(/* values */)
void test_presence(Optional<String> opt, boolean present) {
    assertIsPresent(opt, present)
        .hasValueSatisfying(/* condition */)
        .hasValueSatisfying(/* condition */);
        // ...
}

private OptionalAssert<String> assertIsPresent(Optional<String> opt, boolean present) {
    return present ? assertThat(opt).isPresent() : assertThat(opt).isEmpty();
}

However, if you have separate logic for when value is present or not, I'd suggest you split the test into 2 separate ones, one for each case. Much cleaner like that

Razvan Fulea
  • 437
  • 4
  • 13