什么是惯用的Hamcrest模式断言迭代的每个元素匹配给定的匹配器?

时间:2011-05-12 23:18:14

标签: java idioms hamcrest

检查以下代码段:

    assertThat(
        Arrays.asList("1x", "2x", "3x", "4z"),
        not(hasItem(not(endsWith("x"))))
    );

这断言列表没有不以“x”结尾的元素。当然,这是表示列表中所有元素都以“x”结尾的双重否定方式。

另请注意,该代码段会抛出:

java.lang.AssertionError: 
Expected: not a collection containing not a string ending with "x"
     got: <[1x, 2x, 3x, 4z]>

这列出了整个列表,而不仅仅是不以“x”结尾的元素。

所以有一种惯用的方式:

  • 断言每个元素以“x”结尾(没有双重否定)
  • 关于断言错误,仅列出那些不以“x”结尾的元素

3 个答案:

答案 0 :(得分:23)

您正在寻找everyItem()

assertThat(
    Arrays.asList("1x", "2x", "3x", "4z"),
    everyItem(endsWith("x"))
);

这会产生一个很好的失败信息:

Expected: every item is a string ending with "x"
     but: an item was "4z"

答案 1 :(得分:17)

David Harkness给出的匹配器为预期的部分发出了一个很好的信息。 但是,实际部分的消息也取决于您使用的assertThat方法:

来自 JUnit org.junit.Assert.assertThat)的那个会产生您提供的输出。

  • 使用not(hasItem(not(...)))匹配器:

    java.lang.AssertionError: 
    Expected: not a collection containing not a string ending with "x"
         got: <[1x, 2x, 3x, 4z]>
    
  • 使用everyItem(...)匹配器:

    java.lang.AssertionError: 
    Expected: every item is a string ending with "x"
         got: <[1x, 2x, 3x, 4z]>
    

来自 Hamcrest org.hamcrest.MatcherAssert.assertThat)的那个产生David提供的输出:

  • 使用not(hasItem(not(...)))匹配器:

    java.lang.AssertionError: 
    Expected: not a collection containing not a string ending with "x"
         but: was <[1x, 2x, 3x, 4z]>
    
  • 使用everyItem(...)匹配器:

    java.lang.AssertionError: 
    Expected: every item is a string ending with "x"
         but: an item was "4z"
    

我自己对Hamcrest断言的实验表明,“但是”部分经常令人困惑,这取决于多个匹配器的组合方式以及哪一个首先失败,因此我仍然坚持使用JUnit断言,我完全知道正是我将在“得到”部分看到的内容。

答案 2 :(得分:3)

我知道这个问题已经很老了,但今天,在Java 8中,我宁愿用lambdas写它,例如。

Stream.of("1x", "2x", "3x", "4z").allMatch(e->e.endsWith("x"));

This is why.