Hamcrest Bean Matchers

1. Overview

Hamcrest is a library that provides methods, called matchers, to help
developers write simpler unit tests.
There are plenty of matchers, you
can get started by reading about some of them
here.

In this article, we’ll explore beans matchers.

2. Setup

To get Hamcrest, we just need to add the following Maven dependency to
our pom.xml
:

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>java-hamcrest</artifactId>
    <version>2.0.0.0</version>
    <scope>test</scope>
</dependency>

The latest Hamcrest version can be found on
Maven
Central
.

3. Bean Matchers

Bean matchers are extremely useful to check conditions over POJOs,
something that is frequently required when writing most unit tests.

Before getting started, we’ll create a class that will help us through
the examples:

public class City {
    String name;
    String state;

    // standard constructor, getters and setters

}

Now that we’re all set, let’s see beans matchers in action!

3.1. hasProperty

This matcher is basically to check if certain bean contains a specific
property identified by the property’s name
:

@Test
public void givenACity_whenHasProperty_thenCorrect() {
    City city = new City("San Francisco", "CA");

    assertThat(city, hasProperty("state"));
}

So, this test will pass because our City bean has a property named
state.

Following this idea, we can also test if a bean has certain property and
that property has certain value:

@Test
public void givenACity_whenHasPropertyWithValueEqualTo_thenCorrect() {
    City city = new City("San Francisco", "CA");

    assertThat(city, hasProperty("name", equalTo("San Francisco")));
}

As we can see, hasProperty is overloaded and can be used with a
second matcher to check a specific condition over a property.

So, we can also do this:

@Test
public void givenACity_whenHasPropertyWithValueEqualToIgnoringCase_thenCorrect() {
    City city = new City("San Francisco", "CA");

    assertThat(city, hasProperty("state", equalToIgnoringCase("ca")));
}

Useful, right? We can take this idea one step further with the matcher
that we’ll explore next.

3.2. samePropertyValuesAs

Sometimes when we have to do checks over a lot of properties of a bean,
it may be simpler to create a new bean with the desired values
. Then,
we can check for equality between the tested bean and the new one. Of
course, Hamcrest provides a matcher for this situation:

@Test
public void givenACity_whenSamePropertyValuesAs_thenCorrect() {
    City city = new City("San Francisco", "CA");
    City city2 = new City("San Francisco", "CA");

    assertThat(city, samePropertyValuesAs(city2));
}

This results in fewer assertions and simpler code. Same way, we can test
the negative case:

@Test
public void givenACity_whenNotSamePropertyValuesAs_thenCorrect() {
    City city = new City("San Francisco", "CA");
    City city2 = new City("Los Angeles", "CA");

    assertThat(city, not(samePropertyValuesAs(city2)));
}

Next, well see a couple of util methods to inspect class properties.

3.3. getPropertyDescriptor

There’re scenarios when it may come in handy being able to explore a
class structure.
Hamcrest provides some util methods to do so:

@Test
public void givenACity_whenGetPropertyDescriptor_thenCorrect() {
    City city = new City("San Francisco", "CA");
    PropertyDescriptor descriptor = getPropertyDescriptor("state", city);

    assertThat(descriptor
      .getReadMethod()
      .getName(), is(equalTo("getState")));
}

The object descriptor retrieves a lot of information about the
property state.
In this case, we’ve extracted the getter’s name and
assert that it is equal to some expected value. Note that we can also
apply other text matchers.

Moving on, the last method we will explore is a more general case of
this same idea.

3.4. propertyDescriptorsFor

This method does basically the same as the one in the previous section,
but for all the properties of the bean
. We also need to specify how
high we want to go in the class hierarchy:

@Test
public void givenACity_whenGetPropertyDescriptorsFor_thenCorrect() {
    City city = new City("San Francisco", "CA");
    PropertyDescriptor[] descriptors = propertyDescriptorsFor(
      city, Object.class);

    List<String> getters = Arrays.stream(descriptors)
      .map(x -> x.getReadMethod().getName())
      .collect(toList());

    assertThat(getters, containsInAnyOrder("getName", "getState"));
}

So, what we did here is: get all the property descriptors from the bean
city and stop at the Object level.

Then, we just used Java 8’s features to filter the getter methods.

Finally, we used collections matchers to check something over the
getters list. You can find more information about collections matchers
here.

4. Conclusion

Hamcrest matchers consist of a great set of tools to be used across
every project. They’re easy to learn and become extremely useful in
short time.

Beans matchers in particular, provide an effective way of making
assertions over POJOs
, something that is frequently required when
writing unit tests.

To get the complete implementation of this examples, please refer to
the
GitHub project
.

Leave a Reply

Your email address will not be published.