Hamcrest is a matcher framework as they stated. It has implementations for several languages also. Let’s look at how to use Hamcrest with Junit5 to write more readable self-explanatory assertions in unit tests.
Setting Up Project
Let’s use Junit5 BOM as we previously did. Starting from Hamcrest version 2, there is only one artifact is available. If you are using Junit4 with Hamcrest2, you may have to get your dependencies correct as suggested here.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.aptkode</groupId> <artifactId>unit-test-series</artifactId> <version>1.0-SNAPSHOT</version> <properties> <allure-maven.version>2.10.0</allure-maven.version> <allure-junit5.version>2.13.0</allure-junit5.version> <aspectj.version>1.9.1</aspectj.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.junit</groupId> <artifactId>junit-bom</artifactId> <version>5.7.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest</artifactId> <version>2.2</version> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <release>13</release> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> </plugin> </plugins> </build> </project>
First Assertion Using Hamcrest with Junit5
Let’s assume we have a person, let’s assert his age is 25.
@Test void beanPropertyTest() { Person jhon = new Person("jhon"); assertThat(jhon, hasProperty("name", is("jhon"))); }
Why Hamcrest with Junit5 produce more declarative tests?
We have been using assertEquals method for decades. Do you remember the parameters? Which one is the expected parameter, is it the first one? I’m getting lost each time, with the help of the newer IDEs its not much of a problem. Let’s assume we have a new engineer in our team. At first, he needs to understand the test and context before identifying what assertEquals. Let’s have a look at following Junit5 test.
@Test void beanPropertyTest() { Person person = new Person("jhon"); assertEquals("jhon", person.getName()); }
Let’s write it using Hamcrest.
@Test void beanPropertyTest() { Person person = new Person("jhon"); assertThat(person.getName(), is("jhon")); }
It’s more readable now. Isn’t it? Also Let’s look at error messages produced by two assertion methodologies.


If you want it to more redable, you can use describeAs
wrapper method to format the message as you want. Have a look at following test case. You could also use variables to form a templated message.
@Test void beanPropertyTest() { Person person = new Person("mike"); assertThat(person.getName(), describedAs("person name is jhon",is("jhon"))); }
Above test failure produces following error message.

I think now you can decide what produces more readable tests.
Next, we’ll have a look at various scenarios that Hamcrest produce more readable assertions. Also you can jump into the video tutorial if you are a visual and audio learner.
The Hamcrest Cheat List
Assert Java bean has a property with a value
@Test void beanPropertyTest() { Person jhon = new Person("jhon"); assertThat(jhon, hasProperty("name", is("jhon"))); }
Verify variable is a particular type
@Test void typeTest() { Person jhon = new Person("jhon"); assertThat(jhon.getName(), isA(String.class)); assertThat(jhon.getName(), instanceOf(String.class)); }
Assert variable is holding an exact value
@Test void valueTest() { Person jhon = new Person("jhon"); assertThat(jhon.getName(), is("jhon")); }
Check something is in an array
@Test void isInArrayTest() { Integer[] numbers = new Integer[]{1, 2, 3, 4, 5}; assertThat(2, in(numbers)); assertThat(numbers, hasItemInArray(2)); assertThat(2, oneOf(numbers)); }
Verify something is in a list
@Test void isInListTest() { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); assertThat(2, in(numbers)); assertThat(numbers, hasItem(2)); }
Check size of a collection with bound checking
@Test void listHasSizeTest() { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); assertThat(numbers, hasSize(5)); // assert upper bound assertThat(numbers, hasSize(lessThan(10))); // assert lower bound assertThat(numbers, hasSize(greaterThan(4))); }
Assert map has a certain key
@Test void mapHasKeyTest() { Map<String, Integer> numbers = Stream.of(1, 2, 3, 4, 5) .collect(Collectors.toMap(String::valueOf, v -> v)); assertThat(numbers, hasKey("1")); // assert key with non null value assertThat(numbers, hasEntry(is("1"), notNullValue())); }
Assert map has a certain value
@Test void mapHasValueTest() { Map<String, Integer> numbers = Stream.of(1, 2, 3, 4, 5) .collect(Collectors.toMap(String::valueOf, v -> v)); assertThat(numbers, hasValue(2)); }
Validate that list has values in exact order
@Test void listHasItemsInOrderTest() { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); assertThat(numbers, contains(1, 2, 3, 4, 5)); }
Assert that list has values in any order
@Test void listHasItemsInAnyOrderTest() { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); assertThat(numbers, containsInAnyOrder(5, 4, 3, 2, 1)); }
Assert a collection has items in relative order
@Test void listHasItemRelativeOrderTest() { List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); assertThat(numbers, containsInRelativeOrder(3, 4)); }
Check string ends with something
@Test void stringEndsWithTest() { assertThat("aptkode.com", endsWith("com")); assertThat("aptkode.com", endsWithIgnoringCase("COM")); }
Assert string contains something
@Test void stringContainsTest() { assertThat("aptkode.com", containsString("kode")); assertThat("aptkode.com", containsStringIgnoringCase("KODE")); }
Check string starts with something
@Test void stringStartsWithTest() { assertThat("aptkode.com", startsWith("apt")); assertThat("aptkode.com", startsWithIgnoringCase("APT")); }
Assert bounds of a number like less than, greater than and so on
@Test void assertBoundsTest() { assertThat(1, lessThan(2)); assertThat(5, lessThanOrEqualTo(5)); assertThat(2, greaterThan(1)); assertThat(5, greaterThanOrEqualTo(5)); }
Assert monetize values more declaratively using big decimal matchers
@Test void assertMoneyTest() { assertThat(new BigDecimal("102.4"), closeTo(new BigDecimal(100), new BigDecimal("2.5"))); }
Negate assertions in style
@Test void negateAssertionsTest() { assertThat("aptkode.com", not(startsWith("google"))); assertThat(5, not(in(Arrays.asList(1, 2, 3)))); }
Combine assertions with operators like logical or
and logical and
@Test void combineAssertionsTest(){ assertThat("aptkode.com", both(startsWith("apt")).and(endsWith("com"))); assertThat("aptkode", either(startsWith("apt")).or(startsWithIgnoringCase("APT"))); }
Make sure multiple assertions met in one go
@Test void allAssertionsTest(){ assertThat("aptkode.com", allOf(startsWith("apt"), endsWith("com"), containsString("kode"))); }
Make sure one of the assertions are met
@Test void anyAssertionsTest(){ assertThat("aptkode.com", anyOf(startsWith("com"), containsString("bla"), startsWith("apt"))); }
Extendability of Hamcrest
The most valuable thing with Hamcrest is its extendability. We could write our matcher which add declarative assertions system for a particular domain. We’ll explore how we can do it in a later article. Also there are lot of community-driven projects that already provide a huge set of custom matchers which may suit your scenario.
Final Words
Hamcrest is a powerful tool if you use it correctly. If you want to learn more about testing head over to our unit testing – novice to savvy tutorials on youtube. There will be more tutorials on this series, so subscribe to get the notification. Thanks for reading.