[英]Hamcrest Matcher for no duplicates in a List of Strings?
I would like a simple hamcrest matcher for finding duplicates of an object in a List<String>
. 我想要一个简单的hamcrest匹配器来查找List<String>
对象的重复项。 This is what I wrote 这就是我写的
for (QuizEntity quiz : quizzes)
for (QuestionEntity question : quiz.getQuestions())
Assert.assertThat("There should be no duplicate questions", 1, Matchers.equalTo(Collections.frequency(questions, question.getQuestion())));
Unfortunately I got this output, which isn't descriptive enough. 不幸的是我得到了这个输出,这不够描述。 Any 任何
java.lang.AssertionError: There should be no duplicate questions
Expected: <20>
but: was <1>
There's actually an implemented method that does exactly this - doesNotHaveDuplicates 实际上有一个实现的方法就是这样做 - doesNotHaveDuplicates
Assertions.assertThat(list).doesNotHaveDuplicates();
you could take quizzes and map it using Java 8 to the questions and assert there are no duplicates 您可以使用Java 8进行测验并将其映射到问题,并断言没有重复
Another option is to use hasDistinctElements()
matcher from Cirneco library (that at the end is an Hamcrest extension). 另一种选择是使用来自Cirneco库的 hasDistinctElements()
匹配器(最后是Hamcrest扩展)。
It can be used as follows: 它可以使用如下:
Assert.assertThat("There should be no duplicate questions", questions, CirnecoMatchersJ7.hasDistinctElements());
while I suggest to do 虽然我建议这样做
import static CirnecoMatchersJ7.*;
to make it more human readable 使其更具人性化
assertThat("There should be no duplicate questions", questions, hasDistinctElements());
Cirneco also has some fluent representation, ie Cirneco也有一些流利的代表,即
given(questions).withReason("There should be no duplicate questions").assertThat(hasDistinctElements());
The dependency can be imported as follows: 可以按如下方式导入依赖项:
<dependency>
<groupId>it.ozimov</groupId>
<artifactId>java7-hamcrest-matchers</artifactId>
<version>0.7.0</version>
</dependency>
Replaced 更换
Assert.assertThat("There should be no duplicate questions", 1, Matchers.equalTo(Collections.frequency(questions, question.getQuestion())));
with 同
Assert.assertThat("Question '" + question.getQuestion() + "' should not be duplicated", 1, Matchers.equalTo(Collections.frequency(questions, question.getQuestion())));
I implemented my own matcher for that. 我为此实现了自己的匹配器。 Please note the error message did not work correctly to me (displayed another entry than the duplicate one). 请注意错误消息对我不正常(显示另一个条目而不是重复条目)。 I share the code with the community (please link and upvote if you want to use in your product) 我与社区分享代码(如果您想在产品中使用,请链接和upvote)
public static class DistinctMatcher<T> extends BaseMatcher<T>
{
private final Set<T> theSet = new HashSet<>();
public static <T> Matcher<? super T> distinct()
{
return new DistinctMatcher<T>();
}
@Override
public void describeTo(Description description)
{
description.appendText("has distinct values");
}
@Override
public void describeMismatch(Object item, Description description)
{
description.appendText("element found twice: ").appendValue(item);
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(Object arg0)
{
return theSet.add((T) arg0);
}
}
By maintaining a stateful HashSet
, the matcher is instantiated once and fed by each item of the iteration. 通过维护有状态的HashSet
,匹配器被实例化一次并由迭代的每个项目馈送。 According to Set.add
method, it tells you whether the set contains or not the item already, so matching is immediate. 根据Set.add
方法,它告诉您该集合是否包含该项目,因此匹配是立即的。
assertThat(quizzes,(everyItem(hasProperty("questions",everyItem(hasProperty("question",is(distinct())))))));
The above matcher is not suitable for unconstrained lazy collections (eg iterator over billions of records) because the Set
holds a permanent reference to the object. 上面的匹配器不适用于无约束的惰性集合(例如迭代器超过数十亿条记录),因为Set
拥有对象的永久引用。 One could easily modify the matcher to own only the hashCode
of the object, but should keep in mind memory requirements. 可以轻松修改匹配器以仅拥有对象的hashCode
,但应记住内存要求。
Any other set-based solution suffers the same issue 任何其他基于集合的解决方案都会遇到同样的问题
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.