JavaHamcrest
JavaHamcrest copied to clipboard
Request: Lambda Matcher
Create a matcher that takes a lambda as type safe replacement of Matchers.hasProperty(propertyName, valueMatcher)
Sample code:
public class LambdaMatcher<T, S> extends BaseMatcher<T> {
private final Function<T, S> lambda;
private final String description;
private Matcher<S> matcher;
public LambdaMatcher(Function<T, S> lambda, Matcher<S> matcher,
String description) {
this.lambda = lambda;
this.matcher = matcher;
this.description = description;
}
public LambdaMatcher(Function<T, S> lambda, Matcher<S> matcher) {
this(lambda, matcher, "");
}
@SuppressWarnings("unchecked")
@Override
public boolean matches(Object argument) {
return matcher.matches(lambda.apply((T) argument));
}
@Override
public void describeTo(Description description) {
description.appendText(this.description);
}
}
Usage:
assertThat(list, Matchers.hasItem(allOf(
new LambdaMatcher<>(it -> it.getStringElem(), is("el1")),
new LambdaMatcher<>(it -> it.getLongElem(), is(2L)))));
I'd love to get better support for lamdas and other Java 8 features into Hamcrest.
At the moment, Hamcrest 1.x works with Java 5 and greater, Hamcrest 2.x works with Java 7 and greater. For this feature, we'd have to increase the minimum supported version to Java 8.
Issues #206 and #207 discuss various ways we might go about doing that, though we haven't made much progress against those issues yet. I think this feature would have to depend upon those issues being completed first.
Couldn't this be done via an extension? That would also alleviate some of the issues raised in #206 and #207 -> each extension can have their own minimal JDK version
You can try to use hamcrest-more-matchers (available on maven central). Your sample will look like
import static com.github.seregamorph.hamcrest.MoreMatchers.where;
@Test
public void test() {
List<Item> list = Arrays.asList(new Item()
.setStringElem("el-non-match")
.setLongElem(2L));
assertThat(list, hasItem(allOf(
where(Item::getStringElem, is("el1")),
where(Item::getLongElem, is(2L)))));
}
public static class Item {
private String stringElem;
private long longElem;
public String getStringElem() {
return stringElem;
}
public long getLongElem() {
return longElem;
}
public Item setStringElem(String stringElem) {
this.stringElem = stringElem;
return this;
}
public Item setLongElem(long longElem) {
this.longElem = longElem;
return this;
}
}
Please note, the failed message will have convenient diagnostics (method reference resolved as string): after call Item.getStringElem
java.lang.AssertionError:
Expected: a collection containing (Object that matches is "el1" after call Item.getStringElem and Object that matches is <2L> after call Item.getLongElem)
but: Object that matches is "el1" after call Item.getStringElem was "el-non-match"
It works not only in Java 8, but also in Java 11 and 14.
Thanks, switched to hamcrest.MoreMatchers.where. Works like a charm