Strict matching in hamcrest?
Asked Answered
C

2

2

I'm trying to use Hamcrest, but constantly run into the following:

Hamcrest matchers are shortcircuited, so for eg if I write:

 Assert.assertThat(list, everyItem(not(isIn(shouldNotBeInList))));

Just the first faulty element of shouldNotBeInList is reported. I expect tests to tell me as much, as possible.

Could I write assertions in hamcrest, that they report nicely, so that all mismatches are reported, or should I create my own matchers or use another library?

Example output for

List<String> list = Arrays.asList("a", "b", "c");
List<String> shouldNotBeInList = Arrays.asList("c", "e", "a");

Notice no error message for c

Expected: every item is not one of {"c", "e", "a"}
     but: an item was "a"
Cotillion answered 13/10, 2016 at 8:25 Comment(0)
A
3

Hamcrest is a bit tricky when it comes to readable error messages. Some matchers create a helpful message with all errors, others (the most) report only the first error.

Of course you could create your own matcher with a "better" implementation and a good error message. Doing this for one or two matchers is okay, but this could end in reimplementing Hamcrest.

If using another library is an option for you, take a look at AssertJ. The assertion

Assertions.assertThat(list).doesNotContainAnyElementsOf(shouldNotBeInList);

gives this error message:

Expecting
 <["a", "b", "c"]>
not to contain
 <["c", "e", "a"]>
but found
 <["c", "a"]>
Aglimmer answered 13/10, 2016 at 8:56 Comment(0)
L
0
public static void main(String[] args) {
        List<String> list = Arrays.asList("a", "b", "c");
        List<String> shouldNotBeInList = Arrays.asList("c", "e", "a");

        Assert.assertThat(list, everyFullCheck(not(isIn(shouldNotBeInList))));
    }

    public static class EveryFullCheck<T> extends TypeSafeDiagnosingMatcher<Iterable<T>> {
        private final Matcher<? super T> matcher;

        public EveryFullCheck(Matcher<? super T> matcher) {
            this.matcher= matcher;
        }

        @Override
        public boolean matchesSafely(Iterable<T> collection, Description mismatchDescription) {
            boolean matches = true;
            for (T t : collection) {
                if (!matcher.matches(t)) {
                    if (!matches) {
                        mismatchDescription.appendText(", ");
                    }
                    mismatchDescription.appendText("an item ");
                    matcher.describeMismatch(t, mismatchDescription);
                    matches = false;
                }
            }
            return matches;
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("every item is ").appendDescriptionOf(matcher);
        }
    }

    private static <U> EveryFullCheck<U> everyFullCheck(Matcher<? super U> matcher) {
        return new EveryFullCheck<>(matcher);
    }
        }

Expected: every item is not one of {"c", "e", "a"} but: an item was "a", an item was "c"

Lindeman answered 13/10, 2016 at 9:13 Comment(1)
Thanks I could write my custom assertion, but the point of such a library IMHO is to provide meaningful error message by default.Cotillion

© 2022 - 2024 — McMap. All rights reserved.