Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JUnit & hamcrest: could containsInAnyOrder() tell more about the mismatch?

While testing a Set with JUnit and Hamcrest Matchers I've noticed that Matchers.contains() method gives a pretty good clue on what's wrong with the test. On the other hand Matchers.containsInAnyOrder() difference report is almost useless. Here's the test code:

Simple bean:

public class MyBean {
    private Integer id;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }       
}

JUnit test:

import java.util.HashSet;
import java.util.Set;

import org.junit.Test;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

public class MyTest {

    @Test
    public void hamcrestTest() {
        Set<MyBean> beanSet = new HashSet<MyBean>();

        MyBean bean = new MyBean();
        bean.setId(1);
        beanSet.add(bean);

        bean = new MyBean();
        bean.setId(2);
        beanSet.add(bean);

        assertThat(beanSet, contains(
                hasProperty("id", is(1)),
                hasProperty("id", is(3))
                ));
    }
}

As you could see actual bean id's are 1 and 2 while expected ones are 1 and 3 so the test fails.

Test result:

java.lang.AssertionError: 
Expected: iterable over [hasProperty("id", is <1>), hasProperty("id", is <3>)] in any order
     but: Not matched: <MyBean@4888884e

If I switch to Matchers.contains() method then the result is much more informative:

java.lang.AssertionError: 
Expected: iterable containing [hasProperty("id", is <1>), hasProperty("id", is <3>)]
     but: item 0: property 'id' was <2>

Unfortunately, since a Set is not ordered contains() is not an option in this case.


Finally the question:
Is it somehow possible to get a better error report when asserting a Set with hamcrest?

like image 338
Sergey Pauk Avatar asked Nov 01 '22 06:11

Sergey Pauk


1 Answers

Hamcrest seems to have different implementations for how mismatches are reported for the contains and the containsInAnyOrder matchers.

The containsInAnyOrder just gives you the item's toString() value by doing this:

mismatchDescription.appendText("Not matched: ").appendValue(item);

While the contains matcher does a better job by delegating to the actual matcher's describeMismatch():

matcher.describeMismatch(item, mismatchDescription);

Hence you see the hasProperty matcher's additional information in this case but not while using containsInAnyOrder.

I think the best you can do in this case is to implement a toString() for your MyBean class.

There is already an issue reported about this: https://github.com/hamcrest/JavaHamcrest/issues/47

like image 83
K Erlandsson Avatar answered Nov 12 '22 15:11

K Erlandsson