How to check for size AND presence of some items in collections in hamcrest
Asked Answered
D

4

18

I'm using Hamcrest 1.3 and trying to achieve the following in a more compact way.

Consider following test case:

@Test
public void testCase() throws Exception {

    Collection<String> strings = Arrays.asList(
        "string one",
        "string two",
        "string three"
    );

    // variant 1:
    assertThat(strings, hasSize(greaterThan(2)));
    assertThat(strings, hasItem(is("string two")));

    // variant 2:
    assertThat(strings, allOf(
        hasSize(greaterThan(2)),
        hasItem(is("string two"))
    ));
}

the goal here is to check for both size of collection AND some specific items to be included.

Where first variation is possible and accepted, it is not always that easy to do it, because maybe the collection is itself a result of some other operations and therefore it makes more sense to do all the operations on it using an allOf operation. Which is done in second variation above.

However containing the code of second variation will result in following compile time error:

error: no suitable method found for allOf(Matcher<Collection<? extends Object>>,Matcher<Iterable<? extends String>>)

Is there actually any specific way of testing for size AND items of a collection in Hamcrest using a single shot operation (like allOf)?

Dormouse answered 21/10, 2016 at 12:40 Comment(2)
Related #21625092Derwent
@Derwent related in the sense that they are both about hamcrest and collections ;) otherwise re-read the titles!Dormouse
M
20

I think the compiler is not able to sort out the generics. The following is working for me (JDK 8u102):

assertThat(strings, Matchers.<Collection<String>> allOf(
    hasSize(greaterThan(2)),
    hasItem(is("string two"))
));
Miyamoto answered 23/10, 2016 at 11:31 Comment(1)
this indeed works, even if thats a bit away from Hamcrest's basic idea of readability.Dormouse
L
5

I know this question is old but I still want to answer it in case someone needs explanation.

If you want to use allOf(...) just make sure nested matchers return types match. In your test case hasSize returns org.hamcrest.Matcher<java.util.Collection<? extends T>> but hasItem yields org.hamcrest.Matcher<java.lang.Iterable<? super T>>. In this case I'd recommend to use iterableWithSize(int size) where return type is Matcher<java.lang.Iterable<T>>, so you could do:

assertThat(strings, allOf( iterableWithSize(greaterThan(2)), hasItem("string two") ) );

Loveland answered 26/9, 2018 at 17:14 Comment(0)
H
0

Guessing: you will not get there by using existing matchers.

But writing your own matcher ... takes only a few minutes, once you understand how things come together.

Maybe you check out another answer of mine; where I give a complete example how one can write his own matcher. Back then, that took me maybe 15 minutes; although I had never written custom matchers before.

Holocaine answered 21/10, 2016 at 12:47 Comment(1)
I dont have a problem writing own matchers but this seems to me such a necessary thing that I thought some way should exist for doing it.Dormouse
K
0

There is a easy, but to be honest, a bit hidden way to test for list size AND items matching: contains

contains with one Matcher, checks that the iterable (e.g. the list) has only one item AND the item matches the given Matcher

contains(E... items)(arbitrary number of Matchers) checks that that the iterable has AS MANY items as the number of Matchers given AND each item matches one of the given Matchers. Take care that the Matchers do not match more than one item, or the result might not be like you expected

So to sum up contains implicitly checks for correct size (by the amount of Matchers given)

If you are not interested in a given size match, use hasItem/hasItems

Kamenskuralski answered 30/4, 2020 at 8:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.