Test that either one thing holds or another in AssertJ
Asked Answered
G

2

22

I am in the process of converting some tests from Hamcrest to AssertJ. In Hamcrest I use the following snippet:

assertThat(list, either(contains(Tags.SWEETS, Tags.HIGH))
    .or(contains(Tags.SOUPS, Tags.RED)));

That is, the list may be either that or that. How can I express this in AssertJ? The anyOf function (of course, any is something else than either, but that would be a second question) takes a Condition; I have implemented that myself, but it feels as if this should be a common case.

Gadoid answered 4/11, 2014 at 11:27 Comment(0)
T
33

Edited:

Since 3.12.0 AssertJ provides satisfiesAnyOf which succeeds if at least one of the given assertion succeeds,

assertThat(list).satisfiesAnyOf(
    listParam -> assertThat(listParam).contains(Tags.SWEETS, Tags.HIGH),
    listParam -> assertThat(listParam).contains(Tags.SOUPS, Tags.RED)
);

Original answer:

No, this is an area where Hamcrest is better than AssertJ.

To write the following assertion:

Set<String> goodTags = newLinkedHashSet("Fine", "Good");
Set<String> badTags = newLinkedHashSet("Bad!", "Awful");
Set<String> tags = newLinkedHashSet("Fine", "Good", "Ok", "?");

// contains is statically imported from ContainsCondition
// anyOf succeeds if one of the conditions is met (logical 'or') 
assertThat(tags).has(anyOf(contains(goodTags), contains(badTags)));

you need to create this Condition:

import static org.assertj.core.util.Lists.newArrayList;    
import java.util.Collection;    
import org.assertj.core.api.Condition;

public class ContainsCondition extends Condition<Iterable<String>> {
  private Collection<String> collection;
  
  public ContainsCondition(Iterable<String> values) {
    super("contains " + values);
    this.collection = newArrayList(values);
  }
  
  static ContainsCondition contains(Collection<String> set) {
    return new ContainsCondition(set);
  }

  @Override
  public boolean matches(Iterable<String> actual) {
    Collection<String> values = newArrayList(actual);
    for (String string : collection) {
      if (!values.contains(string)) return false;
    }
    return true;
  };
}

It might not be what you if you expect that the presence of your tags in one collection implies they are not in the other one.

Taluk answered 4/11, 2014 at 21:53 Comment(3)
That’s almost the same code I used. It’s a bit cumbersome. The Condition is very similar to the Hamcrest Matcher; the difference is that Hamcrest comes with dozens of them (since that is Hamcrest’s concept, after all). Also, the Hamcrest matchers are really quite versatile, they can be used for anything and can be passed around. That is the price you have to pay for the code completion. Perhaps it would be possible to use a Hamcrest matcher in place of a condition?Gadoid
I agree the code is cumbersome. I was thinking about allowing reusing hamcrest matcher in place of Condition, I'm a bit reluctant because it's a different approach that I'm not a big fan of as I find difficult the discover what is the right macther, but in cases like yours it's a good solution.Taluk
AssertJ 3.9.0 includes support for easily converting Hamcrest matchers into AssertJ conditions: joel-costigliola.github.io/assertj/…Gadoid
S
3

Inspired by this thread, you might want to use this little repo I put together, that adapts the Hamcrest Matcher API into AssertJ's Condition API. Also includes a handy-dandy conversion shell script.

Spiv answered 18/4, 2015 at 11:12 Comment(1)
That looks promising. I’ll give it a try.Gadoid

© 2022 - 2024 — McMap. All rights reserved.