JUnit 和 hamcrest:containsInAnyOrder() 可以告诉我们更多关于不匹配的信息吗?

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

在使用 JUnit 和 Hamcrest Matchers 测试 Set 时,我注意到 Matchers.contains() 方法提供了一个关于测试错误的很好的线索。另一方面 Matchers.containsInAnyOrder() 差异报告几乎没有用。这是测试代码:

简单的bean:

public class MyBean {
    private Integer id;

    public Integer getId() {
        return id;
    }

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

JUnit测试:

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))
                ));
    }
}

如您所见,实际的 bean id 是 12,而预期的是 13,因此测试失败。

测试结果:

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

如果我切换到 Matchers.contains() 方法,那么结果会提供更多信息:

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

不幸的是,由于 Set 未排序 contains() 在这种情况下不是一个选项。


最后的问题:
在使用 hamcrest 断言 Set 时,是否有可能以某种方式获得更好的错误报告?

Hamcrest 似乎对如何报告 containscontainsInAnyOrder 匹配器的不匹配有不同的实现。

containsInAnyOrder 只是通过这样做为您提供项目的 toString() 价值:

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

虽然 contains 匹配器通过委托给实际匹配器的 describeMismatch() 来做得更好:

matcher.describeMismatch(item, mismatchDescription);

因此,在这种情况下,您会看到 hasProperty 匹配器的附加信息,但在使用 containsInAnyOrder 时不会看到。

我认为在这种情况下你能做的最好的事情就是为你的 MyBean class.

实现一个 toString()

已经有关于此问题的报告:https://github.com/hamcrest/JavaHamcrest/issues/47