Hamcrest: test that an Iterable contains all elements of another Iterable [duplicate] - java

I'm trying to compare 2 lists:
assertThat(actual.getList(), is(Matchers.containsInAnyOrder(expectedList)));
But idea
java: no suitable method found for assertThat(java.util.List<Agent>,org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>>)
method org.junit.Assert.<T>assertThat(T,org.hamcrest.Matcher<T>) is not applicable
(no instance(s) of type variable(s) T exist so that argument type org.hamcrest.Matcher<java.lang.Iterable<? extends model.Agents>> conforms to formal parameter type org.hamcrest.Matcher<T>)
method org.junit.Assert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<T>) is not applicable
(cannot instantiate from arguments because actual and formal argument lists differ in length)
How should I write it?

If you want to assert that the two lists are identical, don't complicate things with Hamcrest:
assertEquals(expectedList, actual.getList());
If you really intend to perform an order-insensitive comparison, you can call the containsInAnyOrder varargs method and provide values directly:
assertThat(actual.getList(), containsInAnyOrder("item1", "item2"));
(Assuming that your list is of String, rather than Agent, for this example.)
If you really want to call that same method with the contents of a List:
assertThat(actual.getList(), containsInAnyOrder(expectedList.toArray(new String[expectedList.size()]));
Without this, you're calling the method with a single argument and creating a Matcher that expects to match an Iterable where each element is a List. This can't be used to match a List.
That is, you can't match a List<Agent> with a Matcher<Iterable<List<Agent>>, which is what your code is attempting.

List<Long> actual = Arrays.asList(1L, 2L);
List<Long> expected = Arrays.asList(2L, 1L);
assertThat(actual, containsInAnyOrder(expected.toArray()));
Shorter version of #Joe's answer without redundant parameters.

To complement #Joe's answer:
Hamcrest provides you with four main methods to match a list:
contains Checks for matching all the elements considering the order. If the list has more or fewer elements, it will fail
containsInAnyOrder Checks for matching all the elements, and it doesn't matter the order. If the list has more or fewer elements, will fail
hasItems Checks just for the specified objects it doesn't matter if the list has more
hasItem Checks just for one object it doesn't matter if the list has more
All of them can receive a list of objects and use the equals method for comparison or can be mixed with other matchers like #borjab mentioned:
assertThat(myList , contains(allOf(hasProperty("id", is(7L)),
hasProperty("name", is("testName1")),
hasProperty("description", is("testDesc1"))),
allOf(hasProperty("id", is(11L)),
hasProperty("name", is("testName2")),
hasProperty("description", is("testDesc2")))));
http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#contains(E...)
http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#containsInAnyOrder(java.util.Collection)
http://hamcrest.org/JavaHamcrest/javadoc/1.3/org/hamcrest/Matchers.html#hasItems(T...)

With existing Hamcrest libraries (as of v.2.0.0.0) you are forced to use Collection.toArray() method on your Collection in order to use containsInAnyOrder Matcher.
Far nicer would be to add this as a separate method to org.hamcrest.Matchers:
public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(Collection<T> items) {
return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder((T[]) items.toArray());
}
Actually I ended up adding this method to my custom test library and use it to increase readability of my test cases (due to less verbosity).

For list of objects you may need something like this:
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
import static org.hamcrest.Matchers.is;
#Test
#SuppressWarnings("unchecked")
public void test_returnsList(){
arrange();
List<MyBean> myList = act();
assertThat(myList , contains(allOf(hasProperty("id", is(7L)),
hasProperty("name", is("testName1")),
hasProperty("description", is("testDesc1"))),
allOf(hasProperty("id", is(11L)),
hasProperty("name", is("testName2")),
hasProperty("description", is("testDesc2")))));
}
Use containsInAnyOrder if you do not want to check the order of the objects.
P.S. Any help to avoid the warning that is suppresed will be really appreciated.

Make sure that the Objects in your list have equals() defined on them. Then
assertThat(generatedList, is(equalTo(expectedList)));
works.

To compare two lists with the order preserved (strict order) use.
assertThat(actualList, contains("item1","item2"));
If we want to compare without a specific order we can use below command
assertThat(collection, containsInAnyOrder("item1","item2"));

Related

why do we need the pure <?> in Java?

why do we need the pure <?> in Java?
Does anything passed can only be used as Object ? So it's the same useful as any class casted to Object (only 9 methods could be available)
Thanks
I mean, if you have List< ? > list, you can only use items as Object. This means list.get(0) gives you Object and nothing more. Yes, also I can store to there anything, but is it useful for you? It's like you have a good an expensive thing and put it to a garbage bin. The only you can get from a trash bin is trash. As well you can put any good object of any class to List but get only Object from there with only 9 methods.
There are two scenarios where an unbounded wildcard is a useful approach:
If you are writing a method that can be implemented using functionality provided in the Object class.
When the code is using methods in the generic class that don't depend on the type parameter.For example, List.size, or List.clear. In fact, Class<?> is so often used because most of the methods in Class<T> don't depend on T.
For example, see Collections.swap method:
public static void swap(List<?> list, int i, int j) {
final List l = list;
l.set(i, l.set(j, l.get(i)));
}
Knowing the type does not aid in swapping two elements within a List, so an unbounded wildcard is used. You pass in a List - any List - and the method swaps the indexed elements. There is no type parameter to worry about.
For more information, see: Unbounded Wildcards.
I think the best answer is because sometimes you literally do not know what type a class is parameterized with. As Michael pointed out List<?> is not the same as List<Object>. So ? provides different semantics, which are useful in ensuring program correctness.
Consider two lists. One list is List<String> and the other is List<Integer>. Both of those are Objects, but we still don't want to get them mixed up. We don't want to put a String in the Integer list or vice-versa. So if you have a type declared as List<?>, you cannot safely put any type in that list. The ? could be String or Integer, but you don't know what it is, and you don't want to mix them up, so you can't put either in.
OTOH, List<Object> is just a list of objects, and since you declared it to hold any objects, you can safely put both String and Integer in the list. You said you didn't care what went into the list by declaring it of type Object, so any type is fine. In any meaningful way I can think of, List<Object> is equivalent to a raw type. It's a list that you manage yourself, without help from the compiler.

Unit Test : check if a particular Comparable has been called

Consider this method, I want to write a unit test for it.
public void update(List toUpdate) {
//...
Collections.sort(toUpdate, new SpecificComparator());
//...
}
I would like to ensure we are ordering the given list using the SpecificComparator implementation. Anyway to do this?
I was thinking of using a factory to retrieve the SpecificComparator implementation, so that I could verify with Mockito that we are calling the factory, but that would not ensure me that the list is ordered given this comparator, we could imagine that someone is calling the factory in the method but not ordering the list with it...
Or, I could also verify the ordering of the toUpdate list object, order another list with the same comparator in my unit test and check they are ordered in the same way?
So many answer, all containing one piece of "truth" but missing others. Sad.
Thus: you should absolutely avoid using a mock to test your comparator on sorting calls. Instead you do test two aspects:
You write unit tests for your comparator. Heck, the comparator has one method; with very clear defined semantics. You focus on writing unit tests to test that thing in isolation. Because that is A) easy to do and B) the whole idea of unit tests: you do as much testing on the smallest unit as possible.
You write a few unit tests to ensure your "plumbing" is correct. And you don't mock anything in there. You make sure that a list with known content gets sorted using your comparator; and then you assertThat(actualList, is(expectedList));
Long story short: the Comparator itself is a unit. You start testing that thing; with all corner cases and what not. Then you make sure that the methods that are supposed to sort lists do come back with a sorted list.
And if your code is such that you still need to think about mocking then chances are that your design could be improved to be easy-to-test (and not hard-to-test).
I would say that this isn't a reasonable thing to want to do.
A unit test should only be testing a class at its public interfaces, and since the comparator is a hidden implementation detail, it's none of the unit test's business how the sort order is achieved.
This means that if the implementation changes some day, to achieve the same sort order by some other means, the test will continue to pass -- and that's how things should be.
So, you should test that the output is sorted in the order you expect, but you should not assert anything about an object that's private to the method.
Of course, if you made the Comparator part of the class's API, it would be a different matter:
public class Updater {
private final Comparator sortComparator;
public Updater(Comparator sortComparator) {
this.sortComparator = sortComparator;
}
public void update(List toUpdate) {
//...
Collections.sort(toUpdate, sortComparator);
//...
}
}
... then it would be appropriate to pass a mock Comparator to the constructor, and assert that it has been used -- because now it's of interest to the caller, that the Comparator it's passed in is the one that's being used, and therefore something that should be tested.
The idea is to have lists sorted already as IF the particular comparator was used. This is important because the behavior of the comparator should not change and if it does then new requirements should be written which means your lists used for testing must change. However for the most part you shouldn't be changing the behavior of a single comparator too often. Therefore you should create lists that are sorted already as if the comparator was used, then you can call the following method
public boolean unitTestComparator(List sorted, Comparator comp)
{
List shuffled = new List(sorted);
Collections.shuffle(shuffled);
return sorted.equals(Collections.sort(shuffled, comp));
}
Now you can use multiple tests for various lists to exercise all edge cases for your different comparators. The key to all this is that you know what the lists should look like after the comparator is used, the only tedious part is finding all the edge cases per comparator. You could also run a for loop and on this method to test it as many times as you'd like because you provide the correct format of the list to the method. All it does is randomize the shuffle.
Note this is random testing, you could also add another parameter to the method which could be the list shuffled in the way you want, to find particular edge cases.
which you mentioned above I called it as a "cross test", but I think it is unnecessary, if you really want to achieve it, I give it to you, and let you to think it more. test update a list twice with different comparators and assert the results is you expected.
public class CrossingTest {
#Test
public void sortWithSpecificComparator() throws Throwable {
List<Integer> list = asList(0, 1, 2);
List<Integer> reversedList = asList(2, 1, 0);
Comparator<Integer> originalOrder = (a, b) -> a < b ? -1 : 1;
assertThat(update(list, with(originalOrder)), equalTo(list));
assertThat(update(list, with(originalOrder.reversed()))
, equalTo(reversedList));
}
private List<Integer> update(List<Integer> input, Comparator comparator) {
List<Integer> list = new ArrayList<>(input);
SUT it = new SUT(comparator);
it.update(list);
return list;
}
private Comparator with(Comparator comparator) { return comparator; }
}
class SUT {
private Comparator comparator;
public SUT(Comparator comparator) {
this.comparator = comparator;
}
public void update(List toUpdate) {
Collections.sort(toUpdate, comparator);
}
}
Although you can mock your new object with the following:
SpecificComparator comparator = Mockito.mock(SpecificComparator.class);
Mockito.whenNew(SpecificComparator.class).thenReturn(comparator);
Best approach is always to check the ordering of elements after the method is called rather than checking when/how comparator is used. You can do that by using equals method of List, this is what it says:
Compares the specified object with this list for equality. Returns
true if and only if the specified object is also a list, both lists
have the same size, and all corresponding pairs of elements in the two
lists are equal.

How to JUnit test that two List<E> contain the same elements in the same order?

Context
I am writing a simple JUnit test for the MyObject class.
A MyObject can be created from a static factory method that takes a varargs of String.
MyObject.ofComponents("Uno", "Dos", "Tres");
At any time during the existence of MyObject, clients can inspect the parameters it was created by in the form of a List<E>, through the .getComponents() method.
myObject.ofComponents(); // -> List<String>: { "Uno", "Dos", "Tres" }
In other words, a MyObject both remembers and exposes the list of parameters that brought it into existence. More details about this contract:
The order of getComponents will be the same as the one chosen for object creation
Duplicate subsequent String components are allowed and retained in order
Behaviour on null is undefined (other code guarantees no null gets to the factory)
There are no ways to alter the list of components after object instantiation
I am writing a simple test that creates a MyObject from a list of String and checks that it can return the same list via .getComponents(). I do this immediately but this is supposed to happen at a distance in a realistic code path.
Code
Here my attempt:
List<String> argumentComponents = Lists.newArrayList("One", "Two", "Three");
List<String> returnedComponents =
MyObject.ofComponents(
argumentComponents.toArray(new String[argumentComponents.size()]))
.getComponents();
assertTrue(Iterables.elementsEqual(argumentComponents, returnedComponents));
Question
Is Google Guava Iterables.elementsEqual() the best way, provided I have the library in my build path, to compare those two lists? this is something I have been agonizing about; should I use this helper method which goes over an Iterable<E>.. check size and then iterate running .equals().. or any other of the methods that an Internet search suggests? what's the canonical way to compare lists for unit tests?
Optional insights I would love to get
Is the method test designed reasonably? I am not an expert in JUnit!
Is .toArray() the best way to convert a List<E> to a varargs of E?
Why not simply use List#equals?
assertEquals(argumentComponents, imapPathComponents);
Contract of List#equals:
two lists are defined to be equal if they contain the same elements in the same order.
I prefer using Hamcrest because it gives much better output in case of a failure
Assert.assertThat(listUnderTest,
IsIterableContainingInOrder.contains(expectedList.toArray()));
Instead of reporting
expected true, got false
it will report
expected List containing "1, 2, 3, ..." got list containing "4, 6, 2, ..."
IsIterableContainingInOrder.contain
Hamcrest
According to the Javadoc:
Creates a matcher for Iterables that matches when a single pass over the examined Iterable yields a series of items, each logically equal to the corresponding item in the specified items. For a positive match, the examined iterable must be of the same length as the number of specified items
So the listUnderTest must have the same number of elements and each element must match the expected values in order.
The equals() method on your List implementation should do elementwise comparison, so
assertEquals(argumentComponents, returnedComponents);
is a lot easier.
org.junit.Assert.assertEquals() and org.junit.Assert.assertArrayEquals() do the job.
To avoid next questions: If you want to ignore the order put all elements to set and then compare: Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two))
If however you just want to ignore duplicates but preserve the order wrap you list with LinkedHashSet.
Yet another tip. The trick Assert.assertEquals(new HashSet<String>(one), new HashSet<String>(two)) works fine until the comparison fails. In this case it shows you error message with to string representations of your sets that can be confusing because the order in set is almost not predictable (at least for complex objects). So, the trick I found is to wrap the collection with sorted set instead of HashSet. You can use TreeSet with custom comparator.
For excellent code-readability, Fest Assertions has nice support for asserting lists
So in this case, something like:
Assertions.assertThat(returnedComponents).containsExactly("One", "Two", "Three");
Or make the expected list to an array, but I prefer the above approach because it's more clear.
Assertions.assertThat(returnedComponents).containsExactly(argumentComponents.toArray());
assertTrue()/assertFalse() : to use only to assert boolean result returned
assertTrue(Iterables.elementsEqual(argumentComponents,
returnedComponents));
You want to use Assert.assertTrue() or Assert.assertFalse() as the method under test returns a boolean value.
As the method returns a specific thing such as a List that should contain some expected elements, asserting with assertTrue() in this way : Assert.assertTrue(myActualList.containsAll(myExpectedList)
is an anti pattern.
It makes the assertion easy to write but as the test fails, it also makes it hard to debug because the test runner will only say to you something like :
expected true but actual is false
Assert.assertEquals(Object, Object) in JUnit4 or Assertions.assertIterableEquals(Iterable, Iterable) in JUnit 5 : to use only as both equals() and toString() are overrided for the classes (and deeply) of the compared objects
It matters because the equality test in the assertion relies on equals() and the test failure message relies on toString() of the compared objects.
As String overrides both equals() and toString(), it is perfectly valid to assert the List<String> with assertEquals(Object,Object).
And about this matter : you have to override equals() in a class because it makes sense in terms of object equality, not only to make assertions easier in a test with JUnit.
To make assertions easier you have other ways (that you can see in the next points of the answer).
Is Guava a way to perform/build unit test assertions ?
Is Google Guava Iterables.elementsEqual() the best way, provided I have the library in my build path, to compare those two lists?
No it is not. Guava is not an library to write unit test assertions.
You don't need it to write most (all I think) of unit tests.
What's the canonical way to compare lists for unit tests?
As a good practice I favor assertion/matcher libraries.
I cannot encourage JUnit to perform specific assertions because this provides really too few and limited features : it performs only an assertion with a deep equals.
Sometimes you want to allow any order in the elements, sometimes you want to allow that any elements of the expected match with the actual, and so for...
So using a unit test assertion/matcher library such as Hamcrest or AssertJ is the correct way.
The actual answer provides a Hamcrest solution. Here is a AssertJ solution.
org.assertj.core.api.ListAssert.containsExactly() is what you need : it verifies that the actual group contains exactly the given values and nothing else, in order as stated :
Verifies that the actual group contains exactly the given values and
nothing else, in order.
Your test could look like :
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
#Test
void ofComponent_AssertJ() throws Exception {
MyObject myObject = MyObject.ofComponents("One", "Two", "Three");
Assertions.assertThat(myObject.getComponents())
.containsExactly("One", "Two", "Three");
}
A AssertJ good point is that declaring a List as expected is needless : it makes the assertion straighter and the code more readable :
Assertions.assertThat(myObject.getComponents())
.containsExactly("One", "Two", "Three");
And if the test fails :
// Fail : Three was not expected
Assertions.assertThat(myObject.getComponents())
.containsExactly("One", "Two");
you get a very clear message such as :
java.lang.AssertionError:
Expecting:
<["One", "Two", "Three"]>
to contain exactly (and in same order):
<["One", "Two"]>
but some elements were not expected:
<["Three"]>
Assertion/matcher libraries are a must because these will really further
Suppose that MyObject doesn't store Strings but Foos instances such as :
public class MyFooObject {
private List<Foo> values;
#SafeVarargs
public static MyFooObject ofComponents(Foo... values) {
// ...
}
public List<Foo> getComponents(){
return new ArrayList<>(values);
}
}
That is a very common need.
With AssertJ the assertion is still simple to write. Better you can assert that the list content are equal even if the class of the elements doesn't override equals()/hashCode() while JUnit ways require that :
import org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple.tuple;
import org.junit.jupiter.api.Test;
#Test
void ofComponent() throws Exception {
MyFooObject myObject = MyFooObject.ofComponents(new Foo(1, "One"), new Foo(2, "Two"), new Foo(3, "Three"));
Assertions.assertThat(myObject.getComponents())
.extracting(Foo::getId, Foo::getName)
.containsExactly(tuple(1, "One"),
tuple(2, "Two"),
tuple(3, "Three"));
}
My answer about whether Iterables.elementsEqual is best choice:
Iterables.elementsEqual is enough to compare 2 Lists.
Iterables.elementsEqual is used in more general scenarios, It accepts more general types: Iterable. That is, you could even compare a List with a Set. (by iterate order, it is important)
Sure ArrayList and LinkedList define equals pretty good, you could call equals directly. While when you use a not well defined List, Iterables.elementsEqual is the best choice. One thing should be noticed: Iterables.elementsEqual does not accept null
To convert List to array: Iterables.toArray is easer.
For unit test, I recommend add empty list to your test case.
Some of the solutions make sense and I agree with them. But for me, I would use assertEquals but I would sort the two lists.
assertEquals(sortedExpectedList, sortedActualList);
It is simple and the output still gives you the diff between the actual and the expected.

How to compare equality between EObject when they contained unordered EList?

I'm still a novice in EMF so maybe my question doesn't really make sense or I assume wrong things.
I'm working on a model-driven project, so I defined an ecore metamodel and generated the associate code. Now I'm currently trying to make unit tests and I need to be able to test equality between objects and more particularly between objects which extend EObject.
I tried to use EcoreUtil.equals() to make my tests but it always returns false as my objects contains references in lists (class EList) that are not ordered the same way. However, I explicitly defined in my metamodel that references are not ordered: I want to use them more like Set than List.
So, I finally decided to implements my own equals methods in my genereated *Impl Class, even if its discouraged in the javadoc, but it there another way, more elegant, to test the structural equality between EMF objects without taking into account the order of lists?
Thanks!
You can implement your own class of utilities where you code your own comparison for unordered lists using the EObject default equals method.
You can base your implementation in the
EqualityHelper.equals(List list1, List list2) using list "contains" instead of going by index as that method does.
I wrote the following utility methods in Xtend:
static def boolean equalsTo(Set<? extends EObject> eObjectSet1, Set<? extends EObject> eObjectSet2) {
contains(eObjectSet1, eObjectSet2) && contains(eObjectSet2, eObjectSet1)
}
static def boolean contains(Set<? extends EObject> eObjectSet1, Set<? extends EObject> eObjectSet2) {
eObjectSet1.forall[eObject1 | eObjectSet2.exists[eObject2 | EcoreUtil.equals(eObject1, eObject2)]]
}
This could probably be solved by using an EMap, with the element of the former list as the key and an arbitrary other type, for example EString, as value.
If an element should be in the set, map it to the empty string.
EMap<SomeClass, EString> someSet;
If the list could contain multiple elements, map it to and integer that gives the number of elements.

How do I assert an Iterable contains elements with a certain property?

Assume I want to unit test a method with this signature:
List<MyItem> getMyItems();
Assume MyItem is a Pojo that has many properties, one of which is "name", accessed via getName().
All I care about verifying is that the List<MyItem>, or any Iterable, contains two MyItem instances, whose "name" properties have the values "foo" and "bar". If any other properties don't match, I don't really care for the purposes of this test. If the names match, it's a successful test.
I would like it to be one-liner if possible. Here is some "pseudo-syntax" of the kind of thing I would like to do.
assert(listEntriesMatchInAnyOrder(myClass.getMyItems(), property("name"), new String[]{"foo", "bar"});
Would Hamcrest be good for this type of thing? If so, what exactly would be the hamcrest version of my pseudo-syntax above?
Thank you #Razvan who pointed me in the right direction. I was able to get it in one line and I successfully hunted down the imports for Hamcrest 1.3.
the imports:
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;
the code:
assertThat( myClass.getMyItems(), contains(
hasProperty("name", is("foo")),
hasProperty("name", is("bar"))
));
AssertJ provides an excellent feature in extracting() : you can pass Functions to extract fields. It provides a check at compile time.
You could also assert the size first easily.
It would give :
import static org.assertj.core.api.Assertions;
Assertions.assertThat(myClass.getMyItems())
.hasSize(2)
.extracting(MyItem::getName)
.containsExactlyInAnyOrder("foo", "bar");
containsExactlyInAnyOrder() asserts that the list contains only these values whatever the order.
To assert that the list contains these values whatever the order but may also contain other values use contains() :
.contains("foo", "bar");
As a side note : to assert multiple fields from elements of a List , with AssertJ we do that by wrapping expected values for each element into a tuple() function :
import static org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple;
Assertions.assertThat(myClass.getMyItems())
.hasSize(2)
.extracting(MyItem::getName, MyItem::getOtherValue)
.containsExactlyInAnyOrder(
tuple("foo", "OtherValueFoo"),
tuple("bar", "OtherValueBar")
);
Its not especially Hamcrest, but I think it worth to mention here. What I use quite often in Java8 is something like:
assertTrue(myClass.getMyItems().stream().anyMatch(item -> "foo".equals(item.getName())));
(Edited to Rodrigo Manyari's slight improvement. It's a little less verbose. See comments.)
It may be a little bit harder to read, but I like the type and refactoring safety.
Its also cool for testing multiple bean properties in combination. e.g. with a java-like && expression in the filter lambda.
Try:
assertThat(myClass.getMyItems(),
hasItem(hasProperty("YourProperty", is("YourValue"))));
Assertj is good at this.
import static org.assertj.core.api.Assertions.assertThat;
assertThat(myClass.getMyItems()).extracting("name").contains("foo", "bar");
Big plus for assertj compared to hamcrest is easy use of code completion.
As long as your List is a concrete class, you can simply call the contains() method as long as you have implemented your equals() method on MyItem.
// given
// some input ... you to complete
// when
List<MyItems> results = service.getMyItems();
// then
assertTrue(results.contains(new MyItem("foo")));
assertTrue(results.contains(new MyItem("bar")));
Assumes you have implemented a constructor that accepts the values you want to assert on. I realise this isn't on a single line, but it's useful to know which value is missing rather than checking both at once.
AssertJ 3.9.1 supports direct predicate usage in anyMatch method.
assertThat(collection).anyMatch(element -> element.someProperty.satisfiesSomeCondition())
This is generally suitable use case for arbitrarily complex condition.
For simple conditions I prefer using extracting method (see above) because resulting iterable-under-test might support value verification with better readability.
Example: it can provide specialized API such as contains method in Frank Neblung's answer. Or you can call anyMatch on it later anyway and use method reference such as "searchedvalue"::equals. Also multiple extractors can be put into extracting method, result subsequently verified using tuple().
Alternatively to hasProperty you can try hamcrest-more-matchers where matcher with extracting function. In your case it will look like:
import static com.github.seregamorph.hamcrest.MoreMatchers.where;
assertThat(myClass.getMyItems(), contains(
where(MyItem::getName, is("foo")),
where(MyItem::getName, is("bar"))
));
The advantages of this approach are:
It is not always possible to verify by field if the value is computed in get-method
In case of mismatch there should be a failure message with diagnostics (pay attention to resolved method reference MyItem.getName:
Expected: iterable containing [Object that matches is "foo" after call
MyItem.getName, Object that matches is "bar" after call MyItem.getName]
but: item 0: was "wrong-name"
It works in Java 8, Java 11 and Java 14
With Stream you can also do:
List<String> actual = myList.stream().map(MyClass::getName).collect(toList());
assertThat(actual, hasItem("expectedString1"));
Because with anyMatch() or allMatch(), you know some values in your list are in the list, but there is possibility that your actual list only contains 5 values while in anyMatch() you have 6; you don't know if all values are present or not. With hasItem(), you indeed check every value you want.

Categories