Is there any Hamcrest Matcher for java.util.Optional?
The Hamcrest Optional from Narendra Pathai does great job indeed.
import static com.github.npathai.hamcrestopt.OptionalMatchers.isEmpty;
import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresent;
import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresentAnd;
import static com.github.npathai.hamcrestopt.OptionalMatchers.isPresentAndIs;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@Test
public void testOptionalValue() {
Optional<String> option = Optional.of("value");
assertTrue(option.isPresent()); // the old-fashioned, non-diagnosable assertion
assertThat(option, isPresent());
assertThat(option, isPresentAndIs("value"));
assertThat(option, isPresentAnd(startsWith("v")));
assertThat(option, isEmpty()); // fails
}
The last assertion above fails and produces nice diagnosable message:
java.lang.AssertionError:
Expected: is <Empty>
but: had value "value"
Available on Maven :
<dependency>
<groupId>com.github.npathai</groupId>
<artifactId>hamcrest-optional</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
Presently Java Hamcrest is using 1.6 version and is integrated with many projects that use older version of Java.
So the features related to Java 8 will be added in future versions that are Java 8 compatible. The solution proposed was to have an extension library that supports it, so that anyone who needs can use extension library.
I am the author of Hamcrest Optional and it is now available on Maven central.
Example: Checking if the Optional contains a string starting with some value
import static com.github.npathai.hamcrestopt.OptionalMatchers.hasValue;
import static org.hamcrest.Matchers.startsWith;
Optional<String> optional = Optional.of("dummy value");
assertThat(optional, hasValue(startsWith("dummy")));
Till this works its way into the Hamcrest, or if you can't add an external library. If you are okay with adding a class, the following does the work for an empty optional
class EmptyOptionalMatcher<T> extends BaseMatcher<Optional<T>> {
private Optional<T> optionalActual;
public EmptyOptionalMatcher() {
}
@Override
public boolean matches(Object item) {
optionalActual = (Optional<T>) item;
if (optionalActual == null) {
return false;
}
boolean empty = !optionalActual.isPresent();
return empty;
}
@Override
public void describeTo(Description description) {
description.appendText("optional is empty");
}
@Override
public void describeMismatch(Object item, Description description) {
if (optionalActual == null) {
description.appendText(" optional was NULL?");
} else {
description.appendText(" was: " + optionalActual.get());
}
}
}
Then have a matchers helper or common class with this static method that you can import and use:
public static <T> Matcher<? super Optional<T>> emptyOptional() {
return new EmptyOptionalMatcher<>();
}
Usage as:
assertThat(someOptional, is(emptyOptional()));
OR the negative test as
assertThat(someOptional, is(not(emptyOptional())));
For the moment I have the following information:
- There is an issue and a feature proposal to support it with othe Java 8 types on hamcrest site.
- One user created one and posted on his GitHub as an example. Still not on Maven but working on it.