skip to content

What is Hamcrest, and how does the assertThat(actual, matcher) style of assertion differ from a classic assertEquals(expected, actual)?

level: juniorimportance: must knowfreq 70%

answer

  1. Matcher = tests a value AND describes itself
  2. assertThat(actual, matcher) — actual always first
  3. One verb, swap the matcher
  4. Self-describing failure: 'Expected ... but: was ...'
  5. Same matchers reused by Mockito argThat / REST-assured

basics

~10 s

Hamcrest is a library of reusable 'matcher' objects. Instead of assertEquals(2, x), you write assertThat(x, is(2)). The matcher describes what you expect, reads almost like English, and prints a clear message when it fails.

solid answer

~40 s

Hamcrest is a 'matcher' library used inside tests. A matcher is a small object that knows how to (a) check whether a value satisfies a condition and (b) describe itself and the actual value in words. You assert with assertThat(actual, matcher), e.g. assertThat(name, is(equalTo("Bob"))). Compared to assertEquals(expected, actual), the matcher style reads left-to-right like a sentence, keeps the actual value first, and produces a structured failure message ('Expected: is "Bob" but: was "Alice"') without you writing it. Matchers are also composable and reusable across assertions, and the same matchers work in JUnit assertThat, Mockito argument matching, and REST-assured. The main trade-off is an extra dependency and import noise versus plain JUnit/AssertJ assertions.

go deeper

for a junior

Can write assertThat(x, is(5)) and read the 'Expected ... but: was ...' message; knows actual comes first.

for a middle

Explains the matcher abstraction (tests + describes), knows the import sources, and picks the right matcher for collections/strings.

for a senior

Contrasts Hamcrest with AssertJ/plain JUnit, knows matchers are reused in Mockito/REST-assured, and reasons about readability vs dependency cost.

for a principal

Sets team conventions on assertion style, weighs Hamcrest vs AssertJ for the codebase, and standardises custom-matcher patterns for the domain.

## What problem Hamcrest solves When you write tests you constantly check 'is this value what I expect?'. The oldest style is `assertEquals(expected, actual)` — a method that takes two values and fails if they are not equal. This works but has limits: (1) the argument order (expected first or actual first?) is easy to get wrong and the failure message then lies; (2) every new kind of check (contains, greater-than, matches-regex) needs a new assert method; (3) you often hand-write the failure message. **Hamcrest** is a small library whose central idea is the **Matcher**. A *matcher* is an object that represents a *condition* a value should satisfy — for example 'equal to 5', 'a string containing "err"', or 'a list that has at least one even number'. Crucially a matcher does two things: it can **test** a value (`matches(item)` returns true/false) and it can **describe** itself and what went wrong in human words. ## The assertThat form You combine a value with a matcher using a single entry point: ``` assertThat(actualValue, theMatcher) ``` Read it as a sentence: *assert that actualValue is theMatcher*. For example `assertThat(total, is(equalTo(42)))` reads 'assert that total is equal to 42'. If the condition holds, nothing happens; if it fails, `assertThat` asks the matcher to describe the expectation and the actual value and throws an `AssertionError` such as: ``` Expected: is <42> but: was <40> ``` Notice you wrote *no* message — the matcher generated it. ## How it differs from assertEquals - **Argument order is fixed and meaningful:** the *actual* value is always first, the *matcher* (your expectation) second. There is no expected/actual confusion. - **One verb, many conditions:** instead of `assertEquals`, `assertTrue`, `assertNull`, `assertArrayEquals`, you always say `assertThat(...)` and swap the matcher: `is(...)`, `nullValue()`, `containsString(...)`, `hasItem(...)`. The vocabulary is extensible. - **Self-describing failures:** matchers know how to print themselves, so messages are consistent and detailed without manual strings. - **Reusable & composable:** a matcher is just an object, so you can store it, pass it around, and combine it (e.g. `allOf(...)`). - **Reusable beyond JUnit:** the *same* matcher objects are used by Mockito (`argThat`), REST-assured, and others. ## Terms used above - *Test*: an automated method that exercises code and asserts an expected outcome. - *Assertion*: a check that fails the test (throws `AssertionError`) if a condition is false. - *AssertionError*: the Java error a failed assertion throws; the test framework reports it as a failure. - *Matcher*: the Hamcrest object that both tests and describes a condition. ## Imports (a common stumbling block) Matchers live in `org.hamcrest.Matchers` (or `CoreMatchers`); the assertion entry point in JUnit is `org.junit.Assert.assertThat` (JUnit 4) or `org.hamcrest.MatcherAssert.assertThat`. You usually static-import them so calls read cleanly. Note: JUnit 5 deprecated its built-in `assertThat` and tells you to use `org.hamcrest.MatcherAssert.assertThat` directly — Hamcrest is independent of the test runner.

  • In JUnit 5, which assertThat should you import for Hamcrest?
    org.hamcrest.MatcherAssert.assertThat — JUnit 5 deprecated/removed its own assertThat in favour of using Hamcrest's entry point directly.
  • Why is the actual value placed first rather than the expectation?
    So the call reads as a left-to-right sentence ('assert that actual is matcher') and the matcher (the expectation) can be an arbitrarily rich, composable object.

saying these in an interview costs you the question

  • Saying the order is assertThat(expected, actual) — the actual value comes first
  • Thinking Hamcrest is a test runner like JUnit — it is only a matcher library
  • Claiming you must write the failure message yourself — the matcher generates it
  • Confusing org.hamcrest.MatcherAssert.assertThat with JUnit5's deprecated Assertions.assertThat

context