Сравнение двух коллекций с помощью метода hamcrest contains()
у меня есть две коллекции, которые я пытаюсь сравнить для равенства в моих модульных тестах, но я борюсь с методом 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));
}
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)
пожалуйста, вы можете помочь мне, где я ошибаюсь с использованием 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;
}
}
3 ответов
коллекции .contains(...)
использует equals
и hashCode
методы объектов. Для того, чтобы использовать equals
(или в данном случае contains
) на ваших собственных объектах вам нужно переопределить equals
и hashCode
методы класса. Это связано с тем, что Java использует ссылки за кулисами, поэтому, хотя поле может быть равно, ссылки на объекты не являются.
в 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;
}
если сложить их в Item
-класс contains
будет работать.
EDIT:
я не уверен, но когда я смотрю на ваш код, я думаю, следующим может быть не так:
@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));
}
если вы попробуете вместо следующее:
@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));
}
содержит ли expectedList теперь 4 элемента?
[Item{name=iPhone}, Item{name=Skateboard}, Item{name=iPhone}, Item{name=Skateboard}] --> Expected
[Item{name=iPhone}, Item{name=Skateboard}] --> Actual
в этом случае вы не должны добавить эти два пункта, поскольку они уже присутствуют в списке.
кроме того, вы пытаетесь использовать contains
по всему списку. Обычно contains
используется, чтобы увидеть, если один элемент присутствует в списке. Таким образом, вы можете использовать что-то вроде этого:
for(Item i : expectedList){
assertTrue(actualList.contains(i));
}
или, возможно, что-то вроде этого, если вы используете эти библиотеки:
assertThat(actualList, is(expectedList));
я не уверен, что это причина, и если это исправит это, так как вы используете другой JUnit библиотека тогда я обычно делаю, и я не уверен, что этот синтаксис с утверждениями возможен.
Я действительно не думаю, что вам действительно нужен hamcrest для этого. Не проще ли было бы сделать утверждения одним из следующих способов:
список по-прежнему является объектом в конце дня:
org.junit.Assert.assertEquals(expected, actual)
старая функциональность моды для списков с помощью containsAll(..):
org.junit.Assert.assertTrue(expectedItems.containsAll(actualItems))
использование утверждает равенство массивов:
org.junit.Assert.assertArrayEquals(expectedItems.toArray(), actualItems.toArray())
конечно, вы можете использовать hamcrest as хорошо:
org.hamcrest.MatcherAssert.assertThat(actual, Matchers.containsInAnyOrder(actual.toArray()));
или
org.hamcrest.MatcherAssert.assertThat(actual, Matchers.contains(actual.toArray()));
вы в основном утверждаете, что expectedItems
- список из одного элемента и этот элемент, как ожидается, будет сам список с двумя элементами iPhone
и skateboard
.
утверждать, что expectedItems
и actualItems
имеют одни и те же элементы в том же порядке, попробуйте это:
@Test
public void getAllItems() {
Collection<Item> actualItems = auction.getAllItems(joe);
assertThat(actualItems, contains(iPhone, skateboard));
}
и помните, что assertThat
ожидает "реальных" объект в качестве первого параметра, а не "ожидается".
кроме того, вы можете сделать что-то вроде этого:
@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()])));
}