23

I am looking for a Hamcrest Matcher to unit test methods that return a java.util.Optional type. Something like:

    @Test
    public void get__Null(){

        Optional<Element> element = Element.get(null);      
        assertThat( sasi , isEmptyOptional());
    }

    @Test
    public void get__GetCode(){

        Optional<Element> element = Element.get(MI_CODE);       
        assertThat( sasi , isOptionalThatMatches(allOf(hasproperty("code", MI_CODE),
                                                       hasProperty("id",   notNullValue())));
    }

Is there any implementation available throw the Maven Repository?

borjab
  • 11,149
  • 6
  • 71
  • 98
  • Why don't you just use `equalTo(...)`? – Jaroslaw Pawlak Jun 08 '16 at 13:29
  • There are other ways to test the object. But on some cases the matcher will make our life easier. For example, to assert that one object has a bean with an Optional property with a value when you only want to check some fields. Or if the equals have some special implementation. – borjab Jun 08 '16 at 14:37
  • I am don't know your case well enough, but maybe this library could help you: https://github.com/shazam/shazamcrest – Jaroslaw Pawlak Jun 08 '16 at 14:38

5 Answers5

19

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")));
Narendra Pathai
  • 41,187
  • 18
  • 82
  • 120
3

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>
borjab
  • 11,149
  • 6
  • 71
  • 98
Jan Dolejsi
  • 1,389
  • 13
  • 25
2

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.
borjab
  • 11,149
  • 6
  • 71
  • 98
2

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())));
Deepak
  • 3,648
  • 1
  • 22
  • 17
1

If you only want to verify that an optional field of some object is present/not present, you can use the following idiom:

Expected object:

public class BusinessObject {
    private Long id;
    private String name;
    private Optional<AnotherObject> anotherObject;
}

Hamcrest test would look like this:

assertThat("BusinessObject is not as expected", businessObject, allOf(
                hasProperty("id", equalTo(1L)),
                hasProperty("name", equalTo("Some title")),
                hasProperty("anotherObject", hasProperty("present", equalTo(true)))
        ));
Andreas Gelever
  • 1,736
  • 3
  • 19
  • 25