什么是惯用的 Hamcrest 模式来断言可迭代的每个元素都匹配给定的匹配器?
Posted
技术标签:
【中文标题】什么是惯用的 Hamcrest 模式来断言可迭代的每个元素都匹配给定的匹配器?【英文标题】:What is the idiomatic Hamcrest pattern to assert that each element of an iterable matches a given matcher? 【发布时间】:2011-08-24 13:03:39 【问题描述】:检查以下 sn-p:
assertThat(
Arrays.asList("1x", "2x", "3x", "4z"),
not(hasItem(not(endsWith("x"))))
);
这断言列表中没有不以“x”结尾的元素。当然,这是双重否定的说法,即列表的所有元素都以“x”结尾。
还要注意 sn-p 抛出:
java.lang.AssertionError:
Expected: not a collection containing not a string ending with "x"
got: <[1x, 2x, 3x, 4z]>
这会列出整个列表,而不仅仅是不以“x”结尾的元素。
那么有没有一种惯用的方式:
断言每个元素都以“x”结尾(没有双重否定) 在断言错误时,仅列出那些不以“x”结尾的元素【问题讨论】:
【参考方案1】:您正在寻找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"
【讨论】:
【参考方案2】: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 断言,我对此非常了解正是我将在“得到”部分看到的。
【讨论】:
【参考方案3】:我知道这个问题已经很老了,但是今天,使用 Java 8,我宁愿用 lambdas 编写它,例如
Stream.of("1x", "2x", "3x", "4z").allMatch(e->e.endsWith("x"));
This is why.
【讨论】:
好收获。但在我看来,Harmcrest 仍然会获胜,因为它的失败消息会更详细地说明哪个项目失败以及失败的原因。当然,如果有时间能看到文章中提到的这种 java8 风格的 assertThat API,当然会很好。以上是关于什么是惯用的 Hamcrest 模式来断言可迭代的每个元素都匹配给定的匹配器?的主要内容,如果未能解决你的问题,请参考以下文章