简体   繁体   English

Hamcrest Matcher在字符串列表中没有重复项?

[英]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)

The code 编码

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

}

How it works 这个怎么运作

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方法,它告诉您该集合是否包含该项目,因此匹配是立即的。

Usage: (I tested it on a not-nested collection) 用法:(我在非嵌套集合上测试过它)

assertThat(quizzes,(everyItem(hasProperty("questions",everyItem(hasProperty("question",is(distinct())))))));

Performance considerations 性能考虑因素

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM