java 使用 hamcrest contains() 方法比较两个集合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25385058/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 07:56:10  来源:igfitidea点击:

Comparing two collections using hamcrest contains() method

javahamcrest

提问by M.K.

I have two collections which I am trying to compare for equality in my unit tests, but I am struggling with the contains method. Here is what I have:

我有两个集合,我试图在我的单元测试中比较它们的相等性,但我正在努力使用 contains 方法。这是我所拥有的:

@Test
public void getAllItems() {

    Collection<Item> actualItems = auction.getAllItems(joe);
    Collection<Item> expectedItems = Lists.newArrayList();
    expectedItems.add(iPhone);
    expectedItems.add(skateboard);
    assertThat(expectedItems, contains(actualItems));

}

itemscontains the same objects as expectedItemsso I would expect the assertion to be true but this is the output I get:

items包含与expectedItems我希望断言相同的对象,但这是我得到的输出:

[Item{name=iPhone}, Item{name=Skateboard}]  --> Expected
[Item{name=iPhone}, Item{name=Skateboard}]  --> Actual

java.lang.AssertionError: 
Expected: iterable containing [<[Item{name=iPhone}, Item{name=Skateboard}]>]
     but: item 0: was <Item{name=iPhone}>
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8)

Please can you help me where I am going wrong with using the containsmethod?

请你能帮我在使用该contains方法时出错的地方吗?

public class Item {

    private String name;

    public Item(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String toString() {
        return Objects.toStringHelper(this).add("name", name).toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Item other = (Item) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}

采纳答案by Kevin Cruijssen

A Collection's .contains(...)uses the equalsand hashCodemethods of the Objects. In order to use equals(or in this case contains) on your own Objects, you need to override the equalsand hashCodemethods of your class. This is because Java uses references behind the scenes, so even though the field may be equal, the Object-references are not.

集合.contains(...)使用对象的equalshashCode方法。为了在您自己的对象上使用equals(或在这种情况下contains),您需要覆盖类的equalshashCode方法。这是因为 Java 在幕后使用引用,所以即使字段可能相等,对象引用也不是。

In Eclipse you can generate them using right-mouse click-> Source-> Generate hashCode() and equals().... But, since you never stated you use Eclipse, here is an example of the methods that are generated:

在 Eclipse 中,您可以使用right-mouse click-> Source->生成它们Generate hashCode() and equals()...。但是,由于您从未声明您使用 Eclipse,这里是生成的方法的示例:

// Overriding this class' equals and hashCode methods for Object comparing purposes 
// using the Collection's contains
// contains does the following behind the scenes: Check if both inputs aren't null, 
// check if the HashCodes match, check if the Objects are equal.
// Therefore to use the Collection's contains for Objects with the same fields, we
// need to override the Object's equals and hashCode methods
// These methods below are generated by Eclipse itself using "Source -> Generate 
// hashCode() and equals()..."
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if(this == obj)
        return true;
    if(obj == null)
        return false;
    if(getClass() != obj.getClass())
        return false;
    Item other = (Item) obj;
    if(name == null){
        if(other.name != null)
            return false;
    }
    else if(!name.equals(other.name))
        return false;
    return true;
}

If you add both of these to your Item-class, the containswill work.

如果您将这两个都添加到您的Item-class 中,contains它将起作用。



EDIT:

编辑:

I'm not sure, but when I look at your code I think the following might be wrong:

我不确定,但是当我查看您的代码时,我认为以下内容可能是错误的:

@Test
public void getAllItems() {

    Collection<Item> actualItems = auction.getAllItems(joe);
    Collection<Item> expectedItems = Lists.newArrayList();

    // You first print both lists
    System.out.println(expectedItems);
    System.out.println(items);

    // And then add the two items to the expectedItems
    expectedItems.add(iPhone);
    expectedItems.add(skateboard);
    assertThat(expectedItems, contains(actualItems));
}

If you try the following instead:

如果您尝试以下操作:

@Test
public void getAllItems() {

    Collection<Item> actualItems = auction.getAllItems(joe);
    Collection<Item> expectedItems = Lists.newArrayList();

    // First add both items
    expectedItems.add(iPhone);
    expectedItems.add(skateboard);

    // Then print both lists
    System.out.println(expectedItems);
    System.out.println(items);

    assertThat(expectedItems, contains(actualItems));
}

Does the expectedList now contain 4 items?

预期列表现在是否包含 4 个项目?

[Item{name=iPhone}, Item{name=Skateboard}, Item{name=iPhone}, Item{name=Skateboard}]  --> Expected
[Item{name=iPhone}, Item{name=Skateboard}]  --> Actual

In that case you shouldn't add the two items, since they are already present in the list.

在这种情况下,您不应添加这两个项目,因为它们已存在于列表中。

Also, you're trying to use the containson the entire list. Normally the containsis used to see if a single item is present in the list. So you could either use something like this:

此外,您正在尝试contains在整个列表中使用 。通常contains用于查看列表中是否存在单个项目。所以你可以使用这样的东西:

for(Item i : expectedList){
    assertTrue(actualList.contains(i));
}

or perhaps something like this, in case you use these libraries:

或者可能是这样的,以防您使用这些库

assertThat(actualList, is(expectedList));

I'm not sure if this is the cause and if this will fix it, since you use a different JUnit library then I usually do and I'm not sure if these syntax with the Asserts are possible.

我不确定这是否是原因以及这是否会解决它,因为您使用不同的 JUnit 库,那么我通常会这样做,而且我不确定这些带有断言的语法是否可行。

回答by Olimpiu POP

I really don't think you actually need hamcrest for this. Wouldn't it be easier to make the asserts in one of the following ways:

我真的不认为你真的需要 hamcrest。通过以下方式之一进行断言不是更容易吗:

A list is still an object at the end of the day:

列表在一天结束时仍然是一个对象:

org.junit.Assert.assertEquals(expected, actual)

An old fashion functionality for lists by using containsAll(..):

使用containsAll(..)的旧式列表功能:

org.junit.Assert.assertTrue(expectedItems.containsAll(actualItems))

Using asserts for arrays' equality:

对数组的相等性使用断言:

org.junit.Assert.assertArrayEquals(expectedItems.toArray(), actualItems.toArray())

Of course you can use hamcrestas well:

当然,您也可以使用hamcrest

org.hamcrest.MatcherAssert.assertThat(actual, Matchers.containsInAnyOrder(actual.toArray()));

OR

或者

org.hamcrest.MatcherAssert.assertThat(actual, Matchers.contains(actual.toArray()));

回答by eee

You basically asserting that expectedItemsis a list with one element and this element is expected to be a list itself with the two items iPhoneand skateboard.

您基本上断言这expectedItems是一个包含一个元素的列表,并且该元素应该是一个包含两个项目iPhone和的列表本身skateboard

To assert that expectedItemsand actualItemshave the same elements in the same order try this:

要断言expectedItemsactualItems以相同的顺序具有相同的元素,请尝试以下操作:

@Test
public void getAllItems() {

    Collection<Item> actualItems = auction.getAllItems(joe);

    assertThat(actualItems, contains(iPhone, skateboard));
}

And beware that assertThatexpects the "actual" object as first parameter and not the "expected".

并注意assertThat将“实际”对象作为第一个参数而不是“预期”对象。

Alternatively you can do something like that:

或者,您可以执行以下操作:

@Test
public void getAllItems() {

    Collection<Item> actualItems = auction.getAllItems(joe);
    Collection<Item> expectedItems = Lists.newArrayList();
    expectedItems.add(iPhone);
    expectedItems.add(skateboard);

    assertThat(actualItems, contains(expectedItems.toArray(new Item[expectedItems.size()])));
}