CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-junit--junit

JUnit is a unit testing framework for Java, created by Erich Gamma and Kent Beck.

Overview
Eval results
Files

matchers.mddocs/

Matchers

JUnit 4 integrates with Hamcrest matchers to provide expressive, readable assertions. Matchers allow you to write assertions in a more natural, English-like syntax and provide better error messages when assertions fail.

Capabilities

Matcher Assertions

Use Hamcrest matchers with JUnit assertions for expressive test verification.

Note: As of JUnit 4.13, the assertThat methods in org.junit.Assert are deprecated. Users should migrate to using Hamcrest's MatcherAssert.assertThat() directly, or use third-party assertion libraries like AssertJ or Google Truth.

Import Consideration: When using Hamcrest matchers, avoid using both import static org.hamcrest.CoreMatchers.* and import static org.hamcrest.Matchers.* together, as many methods exist in both classes and will cause ambiguous reference errors. Use only one wildcard import (typically org.hamcrest.Matchers.* which includes all matchers).

/**
 * Assert using Hamcrest matcher
 * @param actual - Value to test
 * @param matcher - Hamcrest matcher
 * @deprecated Use {@link org.hamcrest.MatcherAssert#assertThat(Object, Matcher)} instead
 */
@Deprecated
public static <T> void assertThat(T actual, Matcher<? super T> matcher);

/**
 * Assert using Hamcrest matcher with custom message
 * @param reason - Message to display on failure
 * @param actual - Value to test
 * @param matcher - Hamcrest matcher
 * @deprecated Use {@link org.hamcrest.MatcherAssert#assertThat(String, Object, Matcher)} instead
 */
@Deprecated
public static <T> void assertThat(String reason, T actual, Matcher<? super T> matcher);

Usage Examples:

import org.junit.Test;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.*;

public class MatcherTest {
    @Test
    public void testWithMatchers() {
        // Equality
        assertThat(5, is(5));
        assertThat("hello", equalTo("hello"));

        // Negation
        assertThat(5, not(3));
        assertThat("hello", not("world"));

        // Null checks
        assertThat(null, nullValue());
        assertThat("text", notNullValue());

        // Type checks
        assertThat("text", instanceOf(String.class));
        assertThat(123, isA(Integer.class));

        // String matchers
        assertThat("hello world", containsString("world"));
        assertThat("hello", startsWith("hel"));
        assertThat("hello", endsWith("lo"));

        // With custom message
        assertThat("Value should be positive", 5, greaterThan(0));
    }

    @Test
    public void testLogicalMatchers() {
        // Any of (OR)
        assertThat(5, either(is(5)).or(is(6)));
        assertThat("test", anyOf(is("test"), is("demo"), is("example")));

        // Both (AND)
        assertThat(5, both(greaterThan(0)).and(lessThan(10)));
        assertThat("test", allOf(startsWith("te"), endsWith("st")));

        // Not
        assertThat(5, not(lessThan(0)));
    }

    @Test
    public void testCollectionMatchers() {
        List<String> items = Arrays.asList("apple", "banana", "cherry");

        // Has item
        assertThat(items, hasItem("banana"));
        assertThat(items, hasItems("apple", "cherry"));

        // Collection properties
        assertThat(items, not(empty()));
        assertThat(items.size(), is(3));

        // Array matchers
        String[] array = {"a", "b", "c"};
        assertThat(array, arrayContaining("a", "b", "c"));
        assertThat(array, arrayContainingInAnyOrder("b", "a", "c"));
    }
}

JUnitMatchers

JUnit-specific matcher utilities that extend Hamcrest matchers with additional functionality.

Note: Most methods in this class are deprecated. Use the equivalent methods from org.hamcrest.CoreMatchers instead. Only isThrowable and isException are not deprecated.

/**
 * JUnit-specific Hamcrest matchers
 */
public class JUnitMatchers {
    /**
     * Matcher for collection containing specific element
     * @param element - Element to find
     * @return Matcher that matches collections containing element
     * @deprecated use {@link org.hamcrest.CoreMatchers#hasItem(Object)}
     */
    @Deprecated
    public static <T> Matcher<Iterable<? super T>> hasItem(T element);

    /**
     * Matcher for collection containing element matching the given matcher
     * @param elementMatcher - Matcher for the element
     * @return Matcher that matches collections containing matching element
     * @deprecated use {@link org.hamcrest.CoreMatchers#hasItem(Matcher)}
     */
    @Deprecated
    public static <T> Matcher<Iterable<? super T>> hasItem(Matcher<? super T> elementMatcher);

    /**
     * Matcher for collection containing all specified elements
     * @param elements - Elements to find
     * @return Matcher that matches collections containing all elements
     * @deprecated use {@link org.hamcrest.CoreMatchers#hasItems(Object...)}
     */
    @Deprecated
    public static <T> Matcher<Iterable<T>> hasItems(T... elements);

    /**
     * Matcher for collection containing elements matching all given matchers
     * @param elementMatchers - Matchers for elements
     * @return Matcher that matches collections with matching elements
     * @deprecated use {@link org.hamcrest.CoreMatchers#hasItems(Matcher...)}
     */
    @Deprecated
    public static <T> Matcher<Iterable<T>> hasItems(Matcher<? super T>... elementMatchers);

    /**
     * Matcher for collection where every element matches the given matcher
     * @param elementMatcher - Matcher that each element must match
     * @return Matcher that matches collections where all elements match
     * @deprecated use {@link org.hamcrest.CoreMatchers#everyItem(Matcher)}
     */
    @Deprecated
    public static <T> Matcher<Iterable<T>> everyItem(Matcher<T> elementMatcher);

    /**
     * Matcher for string containing substring
     * @param substring - Substring to find
     * @return Matcher that matches strings containing substring
     * @deprecated use {@link org.hamcrest.CoreMatchers#containsString(String)}
     */
    @Deprecated
    public static Matcher<String> containsString(String substring);

    /**
     * Combine two matchers with AND
     * @param matcher - First matcher
     * @return CombinableBothMatcher for chaining
     * @deprecated use {@link org.hamcrest.CoreMatchers#both(Matcher)}
     */
    @Deprecated
    public static <T> CombinableBothMatcher<T> both(Matcher<? super T> matcher);

    /**
     * Combine two matchers with OR
     * @param matcher - First matcher
     * @return CombinableEitherMatcher for chaining
     * @deprecated use {@link org.hamcrest.CoreMatchers#either(Matcher)}
     */
    @Deprecated
    public static <T> CombinableEitherMatcher<T> either(Matcher<? super T> matcher);

    /**
     * Matcher for throwable with matching cause, appending stacktrace on mismatch
     * @param throwableMatcher - Matcher for the throwable
     * @return Matcher for Throwable
     */
    public static <T extends Throwable> Matcher<T> isThrowable(Matcher<T> throwableMatcher);

    /**
     * Matcher for exception with matching cause, appending stacktrace on mismatch
     * @param exceptionMatcher - Matcher for the exception
     * @return Matcher for Exception
     */
    public static <T extends Exception> Matcher<T> isException(Matcher<T> exceptionMatcher);
}

Usage Examples:

import org.junit.Test;
import org.junit.matchers.JUnitMatchers;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.*;

public class JUnitMatchersTest {
    @Test
    public void testStringMatcher() {
        assertThat("hello world", JUnitMatchers.containsString("world"));
        assertThat("hello world", JUnitMatchers.containsString("hello"));
    }

    @Test
    public void testCombinedMatchers() {
        // Both conditions must be true
        assertThat(5, JUnitMatchers.both(greaterThan(0)).and(lessThan(10)));

        // Either condition can be true
        assertThat(5, JUnitMatchers.either(is(5)).or(is(10)));
    }

    @Test
    public void testExceptionMatchers() {
        Exception ex = new RuntimeException("Error", new IOException("IO failed"));

        assertThat(ex, JUnitMatchers.isException(
            isA(RuntimeException.class)
        ));
    }
}

Common Hamcrest Matchers

Core matchers from Hamcrest library commonly used with JUnit.

// Object matchers
Matcher<T> equalTo(T operand);
Matcher<T> is(T value);
Matcher<T> not(T value);
Matcher<Object> nullValue();
Matcher<Object> notNullValue();
Matcher<T> sameInstance(T target);
Matcher<T> instanceOf(Class<?> type);
Matcher<T> any(Class<T> type);

// Comparable matchers
Matcher<T> greaterThan(T value);
Matcher<T> greaterThanOrEqualTo(T value);
Matcher<T> lessThan(T value);
Matcher<T> lessThanOrEqualTo(T value);

// String matchers
Matcher<String> containsString(String substring);
Matcher<String> startsWith(String prefix);
Matcher<String> endsWith(String suffix);
Matcher<String> equalToIgnoringCase(String expectedString);
Matcher<String> equalToIgnoringWhiteSpace(String expectedString);
Matcher<String> isEmptyString();
Matcher<String> isEmptyOrNullString();

// Collection matchers
Matcher<Collection<T>> hasItem(T item);
Matcher<Collection<T>> hasItems(T... items);
Matcher<Collection<T>> empty();
Matcher<Collection<T>> hasSize(int size);
Matcher<Iterable<T>> contains(T... items);
Matcher<Iterable<T>> containsInAnyOrder(T... items);

// Array matchers
Matcher<T[]> arrayContaining(T... items);
Matcher<T[]> arrayContainingInAnyOrder(T... items);
Matcher<T[]> arrayWithSize(int size);
Matcher<T[]> emptyArray();

// Logical matchers
Matcher<T> allOf(Matcher<? super T>... matchers);
Matcher<T> anyOf(Matcher<? super T>... matchers);
Matcher<T> not(Matcher<T> matcher);

// Number matchers
Matcher<Double> closeTo(double operand, double error);

Usage Examples:

import org.junit.Test;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.*;

public class HamcrestMatchersTest {
    @Test
    public void testObjectMatchers() {
        assertThat(5, equalTo(5));
        assertThat(5, is(5));
        assertThat(null, nullValue());
        assertThat("text", notNullValue());
        assertThat("text", instanceOf(String.class));
        assertThat("text", any(String.class));

        String s1 = "hello";
        String s2 = s1;
        assertThat(s1, sameInstance(s2));
    }

    @Test
    public void testComparableMatchers() {
        assertThat(10, greaterThan(5));
        assertThat(10, greaterThanOrEqualTo(10));
        assertThat(5, lessThan(10));
        assertThat(5, lessThanOrEqualTo(5));
    }

    @Test
    public void testStringMatchers() {
        assertThat("hello world", containsString("world"));
        assertThat("hello world", startsWith("hello"));
        assertThat("hello world", endsWith("world"));
        assertThat("HELLO", equalToIgnoringCase("hello"));
        assertThat("hello   world", equalToIgnoringWhiteSpace("hello world"));
        assertThat("", isEmptyString());
        assertThat(null, isEmptyOrNullString());
    }

    @Test
    public void testCollectionMatchers() {
        List<String> items = Arrays.asList("apple", "banana", "cherry");

        assertThat(items, hasItem("banana"));
        assertThat(items, hasItems("apple", "cherry"));
        assertThat(items, hasSize(3));
        assertThat(items, not(empty()));
        assertThat(items, contains("apple", "banana", "cherry"));
        assertThat(items, containsInAnyOrder("cherry", "apple", "banana"));
    }

    @Test
    public void testArrayMatchers() {
        String[] array = {"a", "b", "c"};

        assertThat(array, arrayContaining("a", "b", "c"));
        assertThat(array, arrayContainingInAnyOrder("c", "a", "b"));
        assertThat(array, arrayWithSize(3));
        assertThat(new String[0], emptyArray());
    }

    @Test
    public void testLogicalMatchers() {
        // All conditions must be true
        assertThat(5, allOf(greaterThan(0), lessThan(10), not(equalTo(7))));

        // At least one condition must be true
        assertThat(5, anyOf(equalTo(5), equalTo(10), equalTo(15)));

        // Negation
        assertThat(5, not(equalTo(10)));
        assertThat(5, not(lessThan(0)));
    }

    @Test
    public void testNumberMatchers() {
        // Floating point comparison with tolerance
        assertThat(3.14159, closeTo(3.14, 0.01));
        assertThat(0.33333, closeTo(1.0/3.0, 0.001));
    }
}

Custom Matchers

Create custom matchers for domain-specific assertions.

/**
 * Base class for custom matchers
 */
public abstract class TypeSafeMatcher<T> extends BaseMatcher<T> {
    /**
     * Check if item matches
     * @param item - Item to check
     * @return true if matches
     */
    protected abstract boolean matchesSafely(T item);

    /**
     * Describe the matcher
     * @param description - Description to append to
     */
    public abstract void describeTo(Description description);

    /**
     * Describe mismatch
     * @param item - Item that didn't match
     * @param mismatchDescription - Description to append to
     */
    protected void describeMismatchSafely(T item, Description mismatchDescription);
}

Usage Examples:

import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.hamcrest.Matcher;
import org.junit.Test;
import static org.junit.Assert.assertThat;

// Custom matcher for even numbers
public class IsEven extends TypeSafeMatcher<Integer> {
    @Override
    protected boolean matchesSafely(Integer number) {
        return number % 2 == 0;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("an even number");
    }

    @Override
    protected void describeMismatchSafely(Integer item, Description mismatchDescription) {
        mismatchDescription.appendValue(item).appendText(" is odd");
    }

    public static Matcher<Integer> even() {
        return new IsEven();
    }
}

// Custom matcher for valid email
public class IsValidEmail extends TypeSafeMatcher<String> {
    @Override
    protected boolean matchesSafely(String email) {
        return email.matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$");
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("a valid email address");
    }

    public static Matcher<String> validEmail() {
        return new IsValidEmail();
    }
}

// Custom matcher for range
public class InRange extends TypeSafeMatcher<Integer> {
    private final int min;
    private final int max;

    public InRange(int min, int max) {
        this.min = min;
        this.max = max;
    }

    @Override
    protected boolean matchesSafely(Integer value) {
        return value >= min && value <= max;
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("a value between ")
                   .appendValue(min)
                   .appendText(" and ")
                   .appendValue(max);
    }

    @Override
    protected void describeMismatchSafely(Integer item, Description mismatchDescription) {
        mismatchDescription.appendValue(item)
                          .appendText(" is outside range [")
                          .appendValue(min)
                          .appendText(", ")
                          .appendValue(max)
                          .appendText("]");
    }

    public static Matcher<Integer> inRange(int min, int max) {
        return new InRange(min, max);
    }
}

// Usage of custom matchers
public class CustomMatcherTest {
    @Test
    public void testEvenMatcher() {
        assertThat(4, IsEven.even());
        assertThat(2, IsEven.even());
        // assertThat(3, IsEven.even()); // Fails with "3 is odd"
    }

    @Test
    public void testEmailMatcher() {
        assertThat("user@example.com", IsValidEmail.validEmail());
        assertThat("test.user@domain.co.uk", IsValidEmail.validEmail());
        // assertThat("invalid.email", IsValidEmail.validEmail()); // Fails
    }

    @Test
    public void testRangeMatcher() {
        assertThat(5, InRange.inRange(1, 10));
        assertThat(1, InRange.inRange(1, 10));
        assertThat(10, InRange.inRange(1, 10));
        // assertThat(15, InRange.inRange(1, 10)); // Fails with "15 is outside range [1, 10]"
    }
}

// Complex custom matcher with parameters
public class HasProperty<T> extends TypeSafeMatcher<T> {
    private final String propertyName;
    private final Matcher<?> valueMatcher;

    public HasProperty(String propertyName, Matcher<?> valueMatcher) {
        this.propertyName = propertyName;
        this.valueMatcher = valueMatcher;
    }

    @Override
    protected boolean matchesSafely(T obj) {
        try {
            String getterName = "get" + capitalize(propertyName);
            Method getter = obj.getClass().getMethod(getterName);
            Object value = getter.invoke(obj);
            return valueMatcher.matches(value);
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public void describeTo(Description description) {
        description.appendText("has property ")
                   .appendValue(propertyName)
                   .appendText(" matching ")
                   .appendDescriptionOf(valueMatcher);
    }

    public static <T> Matcher<T> hasProperty(String property, Matcher<?> matcher) {
        return new HasProperty<>(property, matcher);
    }

    private String capitalize(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
}

// Usage
@Test
public void testPropertyMatcher() {
    User user = new User("Alice", 25);
    assertThat(user, HasProperty.hasProperty("name", equalTo("Alice")));
    assertThat(user, HasProperty.hasProperty("age", greaterThan(18)));
}

Matcher Composition

Combine matchers to create complex assertions.

Usage Examples:

import org.junit.Test;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.*;

public class MatcherCompositionTest {
    @Test
    public void testComplexComposition() {
        List<String> items = Arrays.asList("apple", "banana", "apricot", "avocado");

        // All items start with 'a' and have length > 5
        assertThat(items, everyItem(
            allOf(
                startsWith("a"),
                hasLength(greaterThan(5))
            )
        ));

        // At least one item equals "banana"
        assertThat(items, hasItem(equalTo("banana")));

        // Collection has size 4 and contains "apple"
        assertThat(items, allOf(
            hasSize(4),
            hasItem("apple")
        ));
    }

    @Test
    public void testNestedMatchers() {
        Map<String, Integer> scores = new HashMap<>();
        scores.put("Alice", 95);
        scores.put("Bob", 87);
        scores.put("Charlie", 92);

        assertThat(scores, allOf(
            hasEntry("Alice", 95),
            hasKey("Bob"),
            hasValue(greaterThan(85))
        ));
    }

    @Test
    public void testObjectPropertyMatchers() {
        User user = new User("Alice", 25, "alice@example.com");

        assertThat(user, allOf(
            hasProperty("name", startsWith("A")),
            hasProperty("age", both(greaterThan(18)).and(lessThan(100))),
            hasProperty("email", containsString("@"))
        ));
    }
}

Benefits of Using Matchers

Improved Readability

// Without matchers
assertTrue(result.size() > 0);
assertTrue(result.contains("expected"));

// With matchers - more readable
assertThat(result, not(empty()));
assertThat(result, hasItem("expected"));

Better Error Messages

// Without matchers
// Expected: true but was: false
assertTrue(name.startsWith("Mr"));

// With matchers - more descriptive
// Expected: a string starting with "Mr" but: was "Ms Smith"
assertThat(name, startsWith("Mr"));

Composable Assertions

// Multiple separate assertions
assertTrue(age >= 18);
assertTrue(age <= 65);
assertNotNull(name);
assertTrue(name.length() > 0);

// Single composed assertion
assertThat(age, allOf(greaterThanOrEqualTo(18), lessThanOrEqualTo(65)));
assertThat(name, allOf(notNullValue(), not(isEmptyString())));

Types

/**
 * Base matcher interface
 */
public interface Matcher<T> extends SelfDescribing {
    boolean matches(Object item);
    void describeMismatch(Object item, Description mismatchDescription);

    @Deprecated
    void _dont_implement_Matcher___instead_extend_BaseMatcher_();
}

/**
 * Base class for matchers
 */
public abstract class BaseMatcher<T> implements Matcher<T> {
    @Override
    public void describeMismatch(Object item, Description description);

    @Override
    public String toString();
}

/**
 * Matcher description
 */
public interface Description {
    Description appendText(String text);
    Description appendDescriptionOf(SelfDescribing value);
    Description appendValue(Object value);
    Description appendList(String start, String separator, String end, Iterable<? extends SelfDescribing> values);
}

/**
 * Combinable matcher for both/and
 */
public class CombinableBothMatcher<T> {
    public CombinableMatcher<T> and(Matcher<? super T> matcher);
}

/**
 * Combinable matcher for either/or
 */
public class CombinableEitherMatcher<T> {
    public CombinableMatcher<T> or(Matcher<? super T> matcher);
}

/**
 * Combined matcher result
 */
public class CombinableMatcher<T> extends TypeSafeMatcher<T> {
    @Override
    protected boolean matchesSafely(T item);

    @Override
    public void describeTo(Description description);
}

Install with Tessl CLI

npx tessl i tessl/maven-junit--junit

docs

annotations.md

assertions.md

assumptions.md

categories.md

index.md

matchers.md

rules.md

standard-runners.md

test-runners.md

theories.md

tile.json