Is there a Hamcrest "for each" Matcher that asserts all elements of a Collection or Iterable match a single specific Matcher?
28,306
Solution 1
Use the Every
matcher.
import org.hamcrest.beans.HasPropertyWithValue;
import org.hamcrest.core.Every;
import org.hamcrest.core.Is;
import org.junit.Assert;
Assert.assertThat(people, (Every.everyItem(HasPropertyWithValue.hasProperty("gender", Is.is("male")))));
Hamcrest also provides Matchers#everyItem
as a shortcut to that Matcher
.
Full example
@org.junit.Test
public void method() throws Exception {
Iterable<Person> people = Arrays.asList(new Person(), new Person());
Assert.assertThat(people, (Every.everyItem(HasPropertyWithValue.hasProperty("gender", Is.is("male")))));
}
public static class Person {
String gender = "male";
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
Solution 2
IMHO this is much more readable:
people.forEach(person -> Assert.assertThat(person.getGender()), Is.is("male"));
Comments
-
E-Riz over 1 year
Given a
Collection
orIterable
of items, is there anyMatcher
(or combination of matchers) that will assert every item matches a singleMatcher
?For example, given this item type:
public interface Person { public String getGender(); }
I'd like to write an assertion that all items in a collection of
Person
s have a specificgender
value. I'm thinking something like this:Iterable<Person> people = ...; assertThat(people, each(hasProperty("gender", "Male")));
Is there any way to do this without writing the
each
matcher myself? -
E-Riz over 8 yearsIt seems that generics is causing problems. I'm getting a compilation problem because
assertThat()
expects argument typesT, Matcher<?super T>
but it's gettingIterable<Person>, Matcher<Iterable<Object>>
-
Sotirios Delimanolis over 8 years@E-Riz I've updated with a full example. If yours is different, please edit your question to include it.
-
E-Riz over 8 yearsYou example still has the generics-related compilation problem, but only when compiled against JDK 7; with JDK 8 it compiles fine. I wasn't aware that the generics spec changed between 7 and 8 but apparently they realized the compiler was being stupid and fixed it.
-
E-Riz over 8 yearsTo get it to compile for Java 7, I had to declare the hasProperty Matcher like this:
HasPropertyWithValue.<Person>hasProperty("gender", is("Male"))
which pretty much destroys the readability improvements that Hamcrest is supposed to provide :-( -
GhostCat over 6 yearsAnd beyond that, woohaaa, reflection and by-string access. I find that super-ugly. I would rather manually iterate the collection and assertThat() on Person::getGender() than ...
-
Petar Mitrovic almost 4 yearsThis is anti-pattern. Asserts should not be placed inside a loop.
-
Raghu about 3 years@PetarMitrovic Why Asserts should not be placed inside loop?
-
Petar Mitrovic about 3 yearsSimply put you won't be able to get the whole picture about the failing asserts as the test runner would exit as soon as it encounters the first failing one.
-
andresp almost 2 yearsbut that is not Hamcrest