Comparing two list of objects in JUnit [duplicate] - java

This question already has answers here:
AssertEquals 2 Lists ignore order
(10 answers)
Java Compare Two Lists
(11 answers)
Closed 6 years ago.
I am writing JUnit Test case for my java project and using Coverage Tool to check the lines of code are covered. The problem is: I've two list of objects. I need to compare the results of object to be equal using assertTrue or any other possible assert statements. I am getting error like Assertion Error by using below assert statements. Is there any solution to compare two lists easily?
//actual
List<ProjectData> actuals = ProjectManagerDao.getProjects("x", "y", "z");
// expected
List<ProjectData> expecteds = new ArrayList<>();
ProjectData p1 = new ProjectData();
p1.setId("a");
p1.setName("b");
expecteds.add(p1);
assertTrue(JsonProvider.getGson().toJson(actuals).equalsIgnoreCase(JsonProvider.getGson().toJson(expecteds)));
//or
assertTrue(actuals.equalIgnoreCase(expeteds);//Not working for list of objects but working for comparing two strings
This differs from Java Compare Two Lists in that I need to be able to assert equality in jUnit, not just compare the lists.

Use Assert.assertArrayEquals(Object[] expecteds, Object[] actuals) method to compare two array for content equality:
Assert.assertArrayEquals(expected.toArray(), actuals.toArray());
equals method compares arrays for being the same reference so it's not suitable in test cases.
For your other question: Remember to use org.junit.Assert not junit.Assert which became obsolete.

In short: there is exactly one assert that one needs when writing JUnit tests: assertThat
You just write code like
assertThat("optional message printed on fails", actualArrayListWhatever, is(expectedArrayListWhatever))
where is() is a hamcrest matcher.
This approach does work for all kinds of collections and stuff; and it does the natural "compare element by element" thing (and there are plenty of other hamcrest matcher that one can use for more specific testing; and it is also pretty easy to write your own matchers).
( seriously; I have not seen a single case where assertThat() would not work; or would result in less readable code )

You can use
Assert.assertEquals(java.lang.Object expected, java.lang.Object actual);
example:
ArrayList<String> list1 = new ArrayList<>();
list1.add("hello");
ArrayList<String> list2 = new ArrayList<>();
list2.add("hello");
Assert.assertEquals(list1, list2);
source: Junit API
or if you want to use the arrays comparison method you can as below
ArrayList<String> list1;
ArrayList<String> list2;
Assert.assertArrayEquals(list1.toArray(), list2.toArray());
I would recommend you to use the assertEquals method.
PS: (the user defined objects stored inside the list should have the equals and hashcode methods overridden)

Related

JUnit - compare unknown Collection and ArrayList

I want to compare Collection (products) (in my case it is LinkedHashMap$LinkedValues) and ArrayList.
The test
assertThat(products, equalTo(Lists.newArrayList(product1, product2, product3)));
doesn't work because LinkedValues doesn't implement equals method.
So I changed my test to:
assertThat(new ArrayList<>(products), equalTo(Lists.newArrayList(product1, product2, product3)));
Is there a better solution where I do not have to check if the collection implements equals method?
Since you're using Hamcrest, you should use the slightly confusingly named method Matchers.contains(). It checks whether the target collection contains the same elements in the same order as the original collection.
Given
Map<String, String> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("a", "A");
linkedHashMap.put("b", "B");
This will pass:
assertThat(linkedHashMap.values(), contains("A", "B"));
and this would fail:
assertThat(linkedHashMap.values(), contains("B", "A"));
Note that Hamcrest has been long dead and even though it works fine and is okay for 99% of usages, you will be shocked by how good AssertJ is, how much functionality it provides and how easy asserting can be.
With AssertJ:
assertThat(linkedHashMap.values()).containsExactly("A", "B");
Assuming the data type you're using already has an equals method, then there's no need to check for an (un-)implemented equals() function. Otherwise, you would have to create something that compares the data you're using.
On a side note, the two lines of code you have are identical. Did you mean to put something else in the second line?
You can use Arrays.equals:
assertTrue(Arrays.equals(products.toArray(), new Product[] {product1, product2, product3}));
This checks array sizes and odering of items. Your product class should implement equals() to be something meaningful.
Note that you can use ArrayList.toArray() to get an array if needed.

How to compare two elements by using one of their attributes using Google Truth (Unit test)

I'm new to the Google Truth library and I was wondering if there was a way to compare two elements by using only one of their attributes. I know it is possible to do so with AssertJ so I was wondering if the same can be achieved with Truth.
I want to do something similar to this.
List list1 = Method1TocreateAList();
List list2 = Method2ToCreateAList();
//other code
//The test I want to achieve
assertThat(list2).compareElementsByUsing(x=>x.id = y)
To compare lists based on a comparison other than plain equality, use comparingElementsUsing:
assertThat(list1).comparingElementsUsing(...).containsExactlyElementsIn(list2);
Add an inOrder() call to the end if you want to check order, too.
The only remaining trick is what to put in that ... section. For your case, since you want to compare on the value of a single field, you can use Correspondence.transforming:
assertThat(list1)
.comparingElementsUsing(
transforming(X::id, "has an ID of"))
.containsExactlyElementsIn(list2);

Incomprehensible JUnit error

Trying to test equality of two Maps (including order) by turning them into lists beforehand. There are probably better ways to do it, but I'd like to know why this error comes up. Here is the test:
#Test
public void sortedEntriesTest() {
List<Map.Entry<String, AtomicInteger>> actualList = stream.sortedEntries(stream.getMap());
List<Map.Entry<String, AtomicInteger>> expectedList =
expectedMap.entrySet()
.stream()
.sorted(Comparator.comparingInt(e -> -e.getValue().get()))
.collect(Collectors.toList());
Assert.assertThat(expectedList, is(actualList));
}
Here is the error:
java.lang.AssertionError:
Expected: is <[file=1, for=1, project=1, is=1, an=1, just=1, example=1, this=2]>
but: was <[file=1, for=1, project=1, is=1, an=1, just=1, example=1, this=2]>
Expected :is <[file=1, for=1, project=1, is=1, an=1, just=1, example=1, this=2]>
Actual :<[file=1, for=1, project=1, is=1, an=1, just=1, example=1, this=2]>
Try
Assert.assertThat(expectedList, is(equalTo(actualList)));
instead.
Explanation:
You are comparing references of two different objects, which are (just as the objects) different. That is why You are getting the AssertionError - first reference is not the second reference.
Solution:
Use the equals method (link to the Java documentation for List.equals()), and it will compare the contents of the lists, also by calling the Map's equals method.
Assert.assertTrue(expectedList.equals(actualList));
Documentation on Assert.assertTrue
Also, check this StackOverflow question and the first (selected) answer - comparing two maps.
Edit
Since You told that the error is still here, then it might be a problem in the list's items. You should check how Map.Entry instances in the expectedList and actualList are being created. Their actual types might be different, since the Map.Entry is just an interface.
Also, I suggest You to use a simpler method of getting the desired values for comparison.

How to assert that two Lists<String> are equal, ignoring order

I am using AssertJ and I am trying to assert that two List<String> contain same strings, ignoring the order.
List<String> expected = Arrays.asList("Something-6144-77.pdf", "d-6144-77.pdf", "something-6144-78.pdf", "Something-6144-8068.pdf");
List<String> actual = new ArrayList<String>();
assertThat(actual.size()).isEqualTo(expected.size());
// This line gives the error: "The method containsExactlyInAnyOrder(String...) in the type ListAssert<String> is not applicable for the arguments (List<String>)"
assertThat(actual).containsExactlyInAnyOrder(expected);
How can I fix the compilation error below that is appearing when trying to use containsExactlyInAnyOrder()?
"The method containsExactlyInAnyOrder(String...) in the type ListAssert is not applicable for the arguments (List)"
Both the answers (by jlordo and by dasblinkenlight) work, but are workarounds rather than the correct way to do it.
There is a method in the AssertJ library for specifically checking if a List contains all values, regardless of order, in another Iterable. It is called containsOnlyElementsOf():
public SELF containsOnlyElementsOf(Iterable<? extends ELEMENT> iterable)
Same semantic as ObjectEnumerableAssert.containsOnly(Object[]) : verifies that actual contains all the elements of the given iterable and nothing else, in any order.
Example :
Iterable<Ring> rings = newArrayList(nenya, vilya);
// assertion will pass
assertThat(rings).containsOnlyElementsOf(newLinkedList(nenya, vilya))
.containsOnlyElementsOf(newLinkedList(nenya, nenya, vilya, vilya));
// assertion will fail as actual does not contain narya
assertThat(rings).containsOnlyElementsOf(newLinkedList(nenya, vilya, narya));
// assertion will fail as actual contains nenya
assertThat(rings).containsOnlyElementsOf(newLinkedList(vilya));
So, this method is the one you should use, like below. There is no need to cast or transform your List to an Array.
assertThat(actual).containsOnlyElementsOf(expected);
As a side note, your assertion on the size of the list is redundant:
assertThat(actual.size()).isEqualTo(expected.size());
This is already covered in the assertion that the lists contain the same elements.
Finally, if you do need to assert that a list has a specific site, AssertJ has a built-in method for this (hasSameSizeAs()):
assertThat(actual).hasSameSizeAs(expected);
The error message gives you the solution:
The method containsExactlyInAnyOrder(String...)
String... is a any number of strings but can be passed as an array as well:
assertThat(actual).containsExactlyInAnyOrder((String[]) expected.toArray(new String[expected.size()]));
The cast is necessary here and that code is given under the assumption that the expected element is created different than in your example, as it doesn't make sense to convert an array to a list and back.
Here some documentation to varargs (Arbitrary number of arguments, the ...): https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
In newer versions of assertj there is a containsExactlyInAnyOrderElementsOf for exactly this purpose.
Your example boils down to
assertThat(actual).containsExactlyInAnyOrderElementsOf(expected);
Since the method takes String..., you should pass an array instead of a list:
String[] expected = new String[] {
"Something-6144-77.pdf"
, "d-6144-77.pdf"
, "something-6144-78.pdf"
, "Something-6144-8068.pdf"
};
or call it with the list of items inlined:
assertThat(actual).containsExactlyInAnyOrder(
"Something-6144-77.pdf"
, "d-6144-77.pdf"
, "something-6144-78.pdf"
, "Something-6144-8068.pdf"
);

Assert that Collection contains 2 Objects with same property using matchers [duplicate]

This question already has answers here:
What is the idiomatic Hamcrest pattern to assert that each element of an iterable matches a given matcher?
(3 answers)
Closed 8 years ago.
I have the following scenario, where I want to test someFunction():
Collection<MyObject> objects = someFunction(someInput);
assertThat(objects , contains(hasProperty("property", is(propertyIWantToTest))));
This works fine if Collection<MyObject> objects should have just 1 MyObject object according to someInput which is passed to someFunction().
However, there are some cases for someInput that the Collection<MyObject> objects should have 2 or more MyObject object containg the same propertyIWantToTest object.
Is there a way to use Hamcrest matchers to test that?
Here's something closer to what I'm willing to achieve:
assertThat(objects , contains(exactlyTwoTimes(hasProperty("property", is(propertyIWantToTest)))));
If you want to verify that every item has that property, and that there are exactly two items, then use everyItem and hasSize:
assertThat(objects, everyItem(hasProperty("property", is(propertyIWantToTest))));
assertThat(objects, hasSize(2));
If you want to specifically test the contents of the collection, but it just so happens that both expected items are the same, use a variable and containsInAnyOrder:
Matcher<MyObject> m = hasProperty("property", is(propertyIWantToTest));
assertThat(objects, containsInAnyOrder(m, m));

Categories

Resources