Hamcrest Matchers.contains matcher not working (?)

13,907

I think you're looking for Matchers.hasItem(..)

Assert.assertThat(items, Matchers.hasItem(Matchers.hasToString("c")));

which states

Creates a matcher for Iterables that only matches when a single pass over the examined Iterable yields at least one item that is matched by the specified itemMatcher. Whilst matching, the traversal of the examined Iterable will stop as soon as a matching item is found.

Matchers.contains, as you stated,

Creates a matcher for Iterables that matches when a single pass over the examined Iterable yields a single item that satisfies the specified matcher. For a positive match, the examined iterable must only yield one item.

It seems to me like that's saying there should only be one element in the Iterable.

Share:
13,907
JulioAragao
Author by

JulioAragao

Updated on July 28, 2022

Comments

  • JulioAragao
    JulioAragao over 1 year

    I am trying to test if a collection has an item which toString() method returns a particular String. I tried do it using excellent Hamcrest matching classes, by combining contains with Matchers.hasToString, but somehow, its Matchers.contains is not being able to match an item even though it is present in the collection.

    Here's an example:

    class Item {
    
        private String name;
    
        public Item(String name){
            this.name = name;
        }
    
        public String toString(){
            return name;
        }
    }
    
    // here's a sample collection, with the desired item added in the end
    Collection<Item> items = new LinkedList<Item>(){{ 
        add(new Item("a")); 
        add(new Item("b"));
        add(new Item("c")); 
    }};
    
    Assert.assertThat(items, Matchers.contains(Matchers.hasToString("c")));
    

    The above assertion is not successful. Here's the message:

    java.lang.AssertionError: 
    Expected: iterable containing [with toString() "c"]
         but: item 0: toString() was "a"
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
        at org.junit.Assert.assertThat(Assert.java:865)
        at org.junit.Assert.assertThat(Assert.java:832)
    

    It looks like the Matchers.contains matcher tries to iterate over the list, but the Matchers.hasToString matcher fails in the first item and invalidates the rest of the iteration. Hamcrest javadoc for Matchers.contains says:

    "Creates a matcher for Iterables that matches when a single pass over the examined Iterable yields a single item that satisfies the specified matcher. For a positive match, the examined iterable must only yield one item"

    Am I doing something wrong?

  • JulioAragao
    JulioAragao about 10 years
    Sotirios, I tried hasItem, but got a compiler error: The method assertThat(T, Matcher<? super T>) in the type Assert is not applicable for the arguments (Collection<Item>, Matcher<Iterable<? super Object>>)
  • Sotirios Delimanolis
    Sotirios Delimanolis about 10 years
    @JulioAragao I copied your example code as is and replaced contains with hasItem.
  • JulioAragao
    JulioAragao about 10 years
    Yes, I guess you're right @Sotirios. I changed the order in the list iterated by the contains matcher so that the "c" appeared first, but even so it doesn't pass. I will investigate why I am having this compilation problem, but I think you nailed it. Thanks!
  • Sotirios Delimanolis
    Sotirios Delimanolis about 10 years
    @julio you can edit your question with details and I'll try to help (but later as I'm away from a PC right now).
  • 0xbe5077ed
    0xbe5077ed about 7 years
    Thanks for the answer! But wow, what a poorly named method. Since when does "contains" mean "is composed of exactly this one thing"?