Issue
Let's say I have a List<A>
where
class A {
private Integer val;
private String name;
}
and in my test case I get this list, with uncertain size, and content. What I wish to do is to compare val
field of two list elements that I know has to be in the list with given name
fields;
List<A> list = logic.getList();
assertThat(list, allOf(hasItems(hasProperty("name", equalTo("first")),
hasItems(hasProperty("val", equalTo(***value from another member with name = "second"))));
How can I achieve this, or is this even possible with Hamcrest Matchers?
Solution
You can implement custom Matcher
for your needs, e.g. to check that some items with names has same values fields:
final class FooTest {
static final class Foo {
final int val;
final String name;
// all args constructor
}
// custom matcher
static final class FoosHasSameValues extends TypeSafeMatcher<List<Foo>> {
private final Set<String> names;
// all args constructor
FoosHasSameValues(final String... names) {
this(new HashSet<>(Arrays.asList(names)));
}
@Override
protected boolean matchesSafely(final List<Foo> items) {
final List<Integer> values = items.stream()
// filter only items with specified names
.filter(i -> this.names.contains(i.name))
// select only values
.map(i -> i.val)
.collect(Collectors.toList());
if (values.size() != this.names.size()) {
// matching failed if list doesn't contains all
// needed items with names
return false;
}
// check https://stackoverflow.com/a/29288616/1723695
return values.stream().distinct().limit(2).count() <= 1;
}
@Override
public void describeTo(final Description description) {
description.appendText("has items [")
.appendValue(String.join(", ", this.names))
.appendText("] with same values");
}
}
@Test
void testMatchers() throws Exception {
MatcherAssert.assertThat(
Arrays.asList(
new Foo("first", 1),
new Foo("second", 1),
new Foo("third", 2)
),
new FoosHasSameValues("first", "second")
);
}
}
Answered By - Kirill
Answer Checked By - Pedro (JavaFixing Volunteer)