Skip to content

Hamcrest extension for Guava

Roberto Trunfio edited this page Jan 28, 2016 · 10 revisions

Introducing the extension

This page describes the Hamcrest extension for JDK7.

How to start

To start using the extension for JDK7, simply import the following dependency in your pom.xml.

<dependency>
  <artifactId>it.ozimov</artifactId>
  <artifactId>cirneco-hamcrest-jdk7</artifactId>
  <version>0.2</version>
  <scope>test</scope>
</dependency>

If you don't use Maven, go here to see how to import using another build automation tool (e.g. Gradle, Grape, etc.).

If you prefer, you can directly import the jar from here:

http://search.maven.org/remotecontent?filepath=it/ozimov/cirneco-hamcrest-jdk7/0.2/cirneco-hamcrest-jdk7-0.2.jar

Once that you have the jar available, in your unit test class you should import all the new matchers as follows:

import static it.ozimov.cirneco.assertions.hamcrest.CirnecoMatchersJ7.*;

There may be a clash with the firm of such another statically imported method from another library, in this case proceed as by practice.

Matchers categories

The library provides matchers divided into the following categories

  • Base - Basic matchers for standard JDK7 classes and Guava base classes.
  • Date - Matchers for Date.
  • Iterable - Matchers for Iterable and some Guava's Iterable implementation, like Multiset.
  • Map - Matchers for Map and Guava's Multimap.
  • Number - Matchers for Number objects, i.e. integers and floating numbers.
  • Web - Matchers for Web-oriented objects, i.e. emails.

Base Matchers

Between matchers

In Cirneco there is a category of general purpose matchers for asserting that an object is between another two objects. The category includes four matchers:

These matchers can be applied to numbers, dates and more in general to any other object that implements Comparable.

An example follows.

//Arrange
Date yesterday = ...; //Init date with date of yesterday
Date tomorrow = ...; //Init date with date of tomorrow
//Act
Date today = methodThatReturnsNow();
//Assert
assertThat("Expected the today to be between yesterday and tomorrow", 
  today, between(yesterday, tomorrow));

Guava Optional matcher

The Guava users may take benefit of the emptyGuavaOptional() matcher. Every time that a method returns an com.google.common.base.Optional, it is convenient to check that the returned Optional is or is not empty as follows:

//Act
Optional optional = methodThatReturnsOptional();
//Assert
assertThat("Expected the returned optional not to be empty", 
  optional, not(is(emptyGuavaOptional()));

Guava Equivalence matcher

Another matchers based on an useful Guava feature is equivalentTo() matcher. Sometimes is convenient to compare objects based on a subset of the object properties.

E.g., suppose to have an entity from a DB and another that has the same fields except the id. Clearly, the equals() method from Object should return false comparing these two objects. However, you can use com.google.common.base.Equivalence to write down a custom equivalence checker that amends the id from the comparison. The following example shows this use case.

//Arrange
Equivalence<MyEntity> entityEquivalence; //Initialize an Equivalence
MyEntity persistedEntity = DAO.findById(1); //retrieve a MyEntity by id from the DB

//Act
MyEntity nonPersistedEntity = methodThatCreateAnEntityWithoutId();

//Assert
assertThat("Expected the two instances to be equivalent", 
  nonPersistedEntity, equivalentTo(pesistedEntity, entityEquivalence));

Same instance matcher

The Hamcrest library already provides a couple of matchers to verify that two objects are the same, i.e. sameInstance() and theInstance() (they are equivalent). Unfortunately both require the instances to be of the same type. This will prevent the possibility to compare the same instance when downcasted to a parent class or interface. Thus, Cirneco provides a new matcher, sameInstance(), to recover from this situation.

Here follows an example.

//Arrange
ArrayList<Object> arrayList = new ArrayList<>();
List<Object> list = arrayList; //Same object as arrayList

//Assert
assertThat("Expected list to be the same instance of arrayList", 
  list, sameInstance(arrayList));

Date Matchers

Cirneco provides a lot of matchers for Date. Generally speaking, these matchers are there to provide support to simple date comparison assertions (e.g. to assert that is specific day of the week) or more complex ones (e.g. is a date with given hour and minute).

Year, month and day matchers

Cirneco provides a set of matchers to assert that a Date object is in a specific year, month or day. The IsDate matcher has a flexible constructor that let you to formulate matchers for all the combinations of the fields year, month and day. For instance, if you want to be sure that now is a day 28 of year 2015, you can do as follows:

//Arrange
Date date = new Date(); //Don't do it at home :) 
int expectedDay = 28;
int expectedMonth = null;
int expectedYear = 2015;

//Assert
assertThat("Expected that today is day 28 of any month of year 2015", 
  now, new IsDate(expectedYear, expectedMonth, expectedDay));

Clearly, there are some convenience static method that can be used without invoking the constructor. They are listed here:


Hour, minute, second and millisecond matchers

In a similar way as for the year, month and day matchers, there are a set of matchers to assert that a Date object is in a specific hour, minute, second or millisecond. The IsDateWithTime matcher has a flexible constructor that let you to formulate matchers for all the combinations of the fields hour, minute, second and millisecond. For instance, if you want to be sure that now is is hour 16 and second 59 (of any minute), you can do as follows:

//Arrange
Date date = new Date(); //Don't do it at home :) 
int expectedHour = 16;
int expectedMinute = null;
int expectedSecond = 59;
int expectedMillisecond = null;

//Assert
assertThat("Expected that now hour 16 and second 59 of any minute and millisecond", 
  now, new IsDateWithTime(expectedHour, expectedMinute, expectedSecond, expectedMillisecond);

Moreover, we support also the 12-hours clock period. So, the previous example would be

//Arrange
Date date = new Date(); //Don't do it at home :) 
int expectedHour = 4;
ClockPeriod clockPeriod = ClockPeriod.PM;
int expectedMinute = null;
int expectedSecond = 59;
int expectedMillisecond = null;

//Assert
assertThat("Expected that now hour 16 and second 59 of any minute and millisecond", 
  now, new IsDateWithTime(expectedHour, clockPeriod, expectedMinute, expectedSecond, expectedMillisecond);

Observer that by default the 24-hours clock period is considered.

To make life easier, there is a set of convenience static method that can be used without invoking the constructor. They are listed here:


Leap year matcher

To assert that a Date object is a leap year, the matcher leapYear() is provided. A simple example follows:

//Arrange
Date date = new Date();

//Assert
assertThat("Expected a leap year", date, leapYear());

Week of the year matcher

To assert that a Date object is in a specific week of the year (i.e. a number between 1 and 53 according to the ISO 8601 standard), the matcher inWeekOfYear() is provided. A simple example follows:

//Act
Date date = methodThatReturnsFirstOfJanuary2016();

//Assert
assertThat("Expected 2016-01-01 to be in week 53 of the year (2015)", date, IsDateInWeekOfYear.inWeekOfYear(53));

Month matchers

To assert that Date object is in a specific month of the year, the twelve matchers january(), february(), ..., december() are provided. A simple example follows:

//Arrange
Date date = new Date();

//Assert
assertThat("Expected the date to be in the month August", date, august());

Week-day matchers

To assert that Date object is in a specific day of the week, the seven matchers monday(), tuesday(), ..., sunday() are provided. A simple example follows:

//Arrange
Date date = new Date();

//Assert
assertThat("Expected the date to be in the day Friday", date, friday());

Iterable Matchers

Cirneco provides some matchers for the interface Iterable. Hamcrest very often differentiates between matchers for interfaces Iterable and Collection, even if the latter extends the latter. Hence, we find more convenient to provide matchers for the former and eventually check if an instance of a Collection is given to get some benefit from methods specifically provided by this interface.

Moreover, some matchers that can be obtained using the base one are now provided ready to use (e.g. see hasSizeOne()).

Empty matcher

Cirneco provides the empty() matcher. It is nothing really new, since Hamcrest has emptyIterable(), but is more easy-to-read and internally calls isEmpty() on the given Iterable whenever it is an instance of a Collection to gain some eventual speed-up.

The common use for this matcher would be:

//Arrange
List<Integer> list = new ArrayList<>(); 

//Assert
assertThat("Expected empty list", list, empty());

Has distinct elements matcher

To assert that an Iterable contains only distinct elements (i.e. has no duplicates), Cirneco provides the [hasDistinctElements()()`](http://ozimov.github.io/cirneco/it/ozimov/cirneco/hamcrest/iterable/IsIterableWithDistinctElements.html#hasDistinctElements--) matcher.

The common use for this matcher would be:

//Arrange
List<Integer> list = new ArrayList<>(); 
list.add(1);
list.add(2);
list.add(3);

//Assert
assertThat("Expected list without duplicates", list, hasDistinctElements()); //Success

Size matchers

Hamcrest provides a matcher to check the size of a Collection (i.e. see hasSize()) and of an Iterable (see iterableWithSize()), but the latter doesn't take any benefit from the type of Iterable (i.e., if it is a Collection you can still use method size()). Cirneco provides new matchers aimed by the same spirit, but more general and effective. In fact, the new matchers are designed to work with any Iterable but to eventually take benefit of the actual implementation.

So, you can use hasSize() also for an Iterable, e.g.

//Arrange
List<Integer> list = new ArrayList<>(); 
list.add(1);

//Assert
assertThat("Expected list with size 1", list, hasSize(1));

but if you are lazy you can use hasSizeOne(), hasSizeTwo(), ..., hasSizeFive(). Even if this seems not really useful or redundant, it is very convenient, for at least two reasons: i) it is more easy-to-read and ii) a good IDE (e.g. IntelliJ) can let you type the initials of the matcher to get it from a dropdown from the autocompletion widget (e.g typing "hso" the hasSizeOne() matcher will appear). So, the previous example is equivalent to the following code.

//Arrange
List<Integer> list = new ArrayList<>(); 
list.add(1);

//Assert
assertThat("Expected list with size 1", list, hasSizeOne());

Multiset element with count matcher

In a Multiset each element has a count. To assert that an element has a given count, the elementWithCount() matcher is provided. A simple example is provided.

//Act
Multiset<String> multiset = methodThatReturnsAMultiset();

//Assert
assertThat("Expected that element \"A\" in the multiset has count 10", multiset, elementWithCount("A", 10));

Sortable matchers

Cirneco introduces new matchers to ascertain that a given Iterable is sorted or sorted in reverse order, with matchers sorted() and sortedReversed(), respectively. These matchers must be used on an Iterable of objects that implement Comparable

If an Iterable of whatsoever objects is given, by verifying that it is sorted it can be used a Comparator along with the two matchers that accept a Comparator, i.e. sorted() and sortedReversed().

Some examples follow:

//Arrange
List<Integer> list = new ArrayList<>(); //Integer implements Comparable
list.add(1);
list.add(2);
list.add(3);

//Assert
assertThat("Expected list to be sorted by using the natural ordering of Integer", 
  list, sorted());

Or with a Comparator you can do as follows.

//Arrange
Comparator<MyObject> comparator; //Init somehow a comparator for class MyObject. 
List<MyObject> list = new ArrayList<>(); //MyObject may not implement Comparable
list.add(...);//Init the list

//Assert
assertThat("Expected list to be sorted by using a custom Comparator for class MyObject", 
  list, sorted(comparator));

The reversed sorting is asserted by the sortedReversed() version of the matcher.

Map Matchers

Same keyset matcher

Sometimes it is convenient to assert that two maps have the same keyset. Thus, here comes the new matcher hasSameKeySet(). The following example shows a possible use case.

//Arrange
Map<String, Integer> comparisonMap = new HashMap<>();
map.put("A", 1);
map.put("B", 2);

//Act
Map<String, Number> actualMap = methodReturningMap();

//Assert
assertThat("Expected actualMap to have the same keyset of comparisonMap", 
  actualMap, hasSameKeySet(comparisonMap));

Multimap element with collection size matcher

In a Multimap, each key maps a Collection of objects. To assert that the size of the collection of a map key is a given value, the matcher keyWithSize() is introduced. An examples follows

//Arrange
String key = "AKey";
Collection<Integer> valuesForKey = ImmutableList.of(1, 100, 100_000);
Multimap<String, Integer> multimap = ArrayListMultimap.create();

//Act
multimap.put("AKey", valuesForKey);

//Assert
assertThat(String.format("Expected a collection size for key \"%s\" equals to 3", key), 
  multimap, keyWithSize(key, 3));

Multimap with keyset matcher

To assert that a Multimap has a given keyset, the matcher hasSameKeySet() can be used. It works with both another Multimap or with a Set. E.g.

//Arrange
Set<String> expectedKeySet = ImmutableSet.of("A", "B", "C");

//Act
Multimap<String, Integer> multimap = methodReturningMultimap;

//Assert
assertThat("Expected a multimap with keyset [\"A\", \"B\", \"C"\]", 
  multimap, hasSameKeySet(expectedKeySet));

Multimap with keyset with size matcher

To deal with the size of the keyset of a Multimap, the matchers emptyKeySet() and keySetWithSize() are provided. An example follows.

//Act
Multimap<String, Integer> multimap = methodReturningMultimap;

//Assert
assertThat("Expected a multimap with non-empty keyset", 
  multimap, not(emptyKeySet()));
assertThat("Expected a multimap with keyset with size 1", 
  multimap, keySetWithSize(1));

Number Matchers

Positive/Negative matchers

To assert that a Number is positive or negative, the positive() and negative() matchers have been added, respectively.


Infinity matchers

To assert that a Number is infinity you can use the new infinity() matcher. An example follows.

//Act
Double number = methodReturningADouble();

//Assert
assertThat("Expected a number equals to positive or negative infinity", number, infinity());

You can be more specific with the matchers negativeInfinity() and positiveInfinity().


Not a number matcher

To assert that a Number does not represent a numeric value you can use the notANumber() matcher.

Web Matchers

This category of matchers aims to support libraries for web based applications. Actually contains only one matcher, but the aim is for a complete coverage of necessary matchers

Email matcher

The email() matcher aims to assert that a given object has a toString() method that returns a valid email address. The matcher uses the Apache email validatorApache email validator. This validator doesn't cover all the possible email addresses. If you are not validating very strange email addresses (are you a spammer?!?) then you can safely use this matcher as long as you trust the Apache validator.

An example follows.

//Assert
assertThat("[email protected]", email());
Clone this wiki locally