Существует ли Hamcrest для каждого Matcher, который утверждает, что все элементы Collection или Iterable соответствуют одному конкретному Matcher?

Учитывая Collection или Iterable элементов, существует ли какой-либо Matcher (или комбинация сопоставителей), который будет утверждать, что каждый элемент соответствует одному Matcher?

Например, для данного типа элемента:

public interface Person {
    public String getGender();
}

Я хотел бы написать утверждение, что все элементы в коллекции Person имеют определенное значение gender. Я думаю примерно так:

Iterable<Person> people = ...;
assertThat(people, each(hasProperty("gender", "Male")));

Есть ли способ сделать это без самостоятельного написания сопоставителя each?


person E-Riz    schedule 04.03.2015    source источник
comment
Вероятно, вы можете использовать средство сопоставления EveryItem: junit.sourceforge.net/javadoc/ org/junit/matchers/   -  person René Winkler    schedule 04.03.2015


Ответы (3)


Используйте сопоставитель Every.

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 также предоставляет Matchers#everyItem в качестве быстрого доступа к что Matcher.


Полный пример

@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;
    }
}
person Sotirios Delimanolis    schedule 04.03.2015
comment
Кажется, что дженерики вызывают проблемы. У меня возникает проблема с компиляцией, потому что assertThat() ожидает типы аргументов T, Matcher<?super T>, но получает Iterable<Person>, Matcher<Iterable<Object>> - person E-Riz; 04.03.2015
comment
@ E-Riz Я обновил полный пример. Если ваш вопрос отличается, отредактируйте свой вопрос, чтобы включить его. - person Sotirios Delimanolis; 04.03.2015
comment
В вашем примере все еще есть проблема компиляции, связанная с дженериками, но только при компиляции с JDK 7; с JDK 8 он компилируется нормально. Я не знал, что спецификация дженериков изменилась между 7 и 8, но, видимо, они поняли, что компилятор ведет себя глупо, и исправили это. - person E-Riz; 04.03.2015
comment
Чтобы скомпилировать его для Java 7, мне пришлось объявить hasProperty Matcher следующим образом: HasPropertyWithValue.<Person>hasProperty("gender", is("Male")) что в значительной степени уничтожает улучшения читабельности, которые должен обеспечить Hamcrest :-( - person E-Riz; 04.03.2015
comment
И помимо этого, woohaaa, отражение и доступ по строке. Я нахожу это супер-уродливым. Я бы предпочел вручную перебрать коллекцию и использовать assertThat() для Person::getGender(), чем... - person GhostCat; 02.08.2017

ИМХО, это намного читабельнее:

people.forEach(person -> Assert.assertThat(person.getGender()), Is.is("male"));
person Markus    schedule 29.04.2019
comment
Это антипаттерн. Утверждения не должны размещаться внутри цикла. - person Petar Mitrovic; 23.01.2020
comment
@PetarMitrovic Почему утверждения не должны помещаться внутри цикла? - person Raghu; 22.10.2020
comment
Проще говоря, вы не сможете получить полную картину об ошибочных утверждениях, поскольку средство запуска тестов завершит работу, как только обнаружит первое ошибочное утверждение. - person Petar Mitrovic; 23.10.2020

Более читаемый, чем утвержденный ответ, и никаких отдельных утверждений в цикле:

import static org.assertj.core.api.Assertions.assertThat;

assertThat(people).allMatch((person) -> {
  return person.gender.equals("male");
});
person xaviert    schedule 03.05.2021