Comparing two collections using the hamcrest contains () method

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

@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 contains the same objects as expectedItems , so I would expect the statement to be true, but this is the result I get:

 [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 help me, where am I wrong using the contains method?

 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; } } 
+6
source share
3 answers

The .contains(...) collection uses the equals and hashCode methods of objects. To use equals (or in this case contains ) in your own objects, you need to override the equals and hashCode methods of your class. This is because Java uses links behind the scenes, so although the field may be the same, object references are not.

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

 // Overriding this class' equals and hashCode methods for Object comparing purposes // using the Collection 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 contains for Objects with the same fields, we // need to override the Object 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 them to the Item class, contains will work.


EDIT:

I'm not sure, but when I look at your code, I think the following may 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:

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

Is a list of 4 items included in the waitlist?

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

In this case, you should not add two elements, since they are already in the list.

In addition, you are trying to use contains for the entire list. Usually contains used to see if a single item is present in a list. So you can use something like this:

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

or maybe something like this if you use these libraries :

 assertThat(actualList, is(expectedList)); 

I'm not sure if this is the reason, and if it is fixed, since you are using a different JUnit library, then I usually do, and I'm not sure if this syntax is possible with Asserts.

+3
source

I really don't think you really need hamcrest for this. It would be easier to make statements in one of the following ways:

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

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

The old-fashion function for lists using contains All (..) :

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

Using statements for equality of arrays:

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

Of course you can use hamcrest :

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

OR

 org.hamcrest.MatcherAssert.assertThat(expected, Matchers.contains(actual.toArray())); 
+1
source

You basically claim that expectedItems is a list with one element, and that element should be a list with two elements iPhone and skateboard .

To claim that expectedItems and actualItems have the same elements in the same order, try this:

 @Test public void getAllItems() { Collection<Item> actualItems = auction.getAllItems(joe); assertThat(actualItems, contains(iPhone, skateboard)); } 

And be careful that assertThat expects the "actual" object as the first parameter, and not the "expected" one.

Alternatively, you can do something like this:

 @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()]))); } 
0
source

Source: https://habr.com/ru/post/974029/


All Articles