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

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

Related

Java Get First Array Item from Optional

I was having some problem when trying to get the first array item out of Optional. Following as my code:
String[] temp = new String[2];
temp[0] = "email1";
temp[1] = "email2";
Optional<String[]> email = Optional.of(temp);
System.out.println(email.map(e -> e.get(0)).orElse(null));
I am trying to get the first email, otherwise just return as null. However, when I run this, I am getting these error messages:
System.out.println(email.map(e -> e.get(0)).orElse(null));
^
symbol: method get(int)
location: variable e of type String[]
1 error
When I tried to do this:
System.out.println(email.stream().findFirst().get());
It prints out weird value:
[Ljava.lang.String;#7adf9f5f
Any ideas? Thanks!
Arrays don't really have methods, per se. .get is something you call on a Collection, not a primitive array. Since the Optional contains an actual, primitive Java array, just use brackets [] to access the element.
System.out.println(email.map(e -> e[0]).orElse(null));
An Optional works alike an if-else test but lay out inside a special object to carry a value and make comparison to an equivalent
You put an "array" as a value into the Optional, the only object get() could return is the array not any of it's elements, also, get() for Optional does not take an argument in it.
The isPresent() boolean and the void
ifPresent(ConsumerAndItsValue cmv) methods are a test to find if the "VALUE" is present, works much more like comparing using if object.equals(this object)
So of you want to use it for particular email addresses you simply put in each string , the tests cannot see into the array, those elements are more objects.
Create a java.util.Consumer≪Anobject> the functional code assigned "to a lambda", Anobject should be the type in accept method accept(T to) method.
Here's a stack overflow page I found
Proper usage of Optional.ifPresent()
And it is possible to iterate over an array contents (external site example). https://mkyong.com/java8/java-8-consumer-examples/

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.

Unsupported Operation on AbstractList.add()

I got a method
foo(list);
that get's a
List<SomeEntit>
as input.
My method foo looks somewhat like the following:
public void foo(List<SomeEntity someEntities) {
someEntities.add(anotherEntity);
}
I then get an "javax.ejb.EJBException: java.lang.UnsupportedOperationException" caused by "java.lang.UnsupportedOperationException: null" at "at java.util.AbstractList.add(AbstractList.java:148)"
Can you tell me why this is happening? I hope that my code example is not too minimal.
Some lists are unmodifiable. The operation of adding elements is then "unsupported".
Java collections framework does not have a distinct type for unmodifiable lists or other unmodifiable collections. You never really know if it is allowed to add something.
All you can do is to specify that the list that is passed must be modifiable.
It seems that the actual type of the List you get as the input does not override the add method.
Try converting that list to a list implementation that does, like ArrayList:
List<SomeEntity> newList = new ArrayList<>(list);
foo(newList);

Hamcrest Matchers - Assert Type of List

The Problem
I'm currently trying to use Hamcrest Matchers to assert that the list type being returned is of a specific type. For example, let's say I have the following List that is being returned by my service call:
List<SomePOJO> myList;
I want to assert that the list being returned is parametrized of type SomePOJO and not TheOtherPOJO. However, it appears that Hamcrest Matchers does not have this sort of functionality.
What I Have Tried
After some research, I have seen the following options:
I have seen that there is hasItem(isA(SomePJO.class)), however this only works if there is an element in the list, and not if the list is empty.
I could use is(instanceOf(List.class)), however this will only assert that the item being returned is a List; it does not assert what type of list is being returned.
I can also add an element to the list immediately before the assert statement and then using assertThat(somePojo.get(0), is(instanceOf(SomePOJO.class))), however this isn't very clean. It is also very similar to point #1.
Conclusion / The Question
Using Hamcrest Matchers, is there a way to assert that an empty list is parametrized of a certain type (such as assertThat(myList, is(aListOf(SomePOJO.class))))?
You can't. This is due to type erasure, you're not able to inspect the generic type. The compiler will enforce this for you. If you really want to test this, one option would be to grab the first element and make sure you can cast it to SomePOJO. (or alternatively grab every element and attempt the cast, but I believe this is overkill).

How are List and List<String> different?

I'd just started working with lists and wanted to know how both of these are different?
Im guessing the second one specifically points out that it contains only string type stuff, while the first one is more flexible.
But then if the first is more flexible, why do people use the second one ever?
It's called generics.
The second one specifies this is a list of Strings and will throw a compiler error if you try to put something else.
It is useful to prevent people from putting anything besides a String in the List.
Here is a link to the java generic tutorial.
List<E> : Its generic and E will be any object i.e it will contain List of Object.
List<String> : The data type of list is string i.e it can only contain String.
It depend on the requirement what is the need of datatype of List.May be whatever example you looked require list of String.

Categories

Resources